AMShipMap.m 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. //
  2. // AMShipMap.m
  3. // Apex Mobile
  4. //
  5. // Created by Jack on 2018/5/4.
  6. // Copyright © 2018年 United Software Applications, Inc. All rights reserved.
  7. //
  8. #import "AMShipMap.h"
  9. #import <MapKit/MapKit.h>
  10. #import "AMMapView.h"
  11. #import "AMAnnotationView.h"
  12. typedef enum {
  13. AMShipAnnotationPriorityRequired,
  14. AMShipAnnotationPriorityHigh,
  15. AMShipAnnotationPriorityLow
  16. } AMShipAnnotationPriority;
  17. @interface AMShipAnnotation : MKPointAnnotation
  18. @property (nonatomic,assign) AMShipAnnotationPriority priority;
  19. @property (nonatomic,copy) NSString *imageName;
  20. @property (nonatomic,assign) BOOL isCurrent;
  21. @end
  22. @implementation AMShipAnnotation
  23. @end
  24. @interface AMShipMap () <MKMapViewDelegate>
  25. {
  26. MKAnnotationView *_currentAnnotaion;
  27. NSTimer *_twinkleTimer;
  28. float _timerAngle;
  29. }
  30. @property (nonatomic,strong) AMMapView *mapView;
  31. @property (nonatomic,strong) UIButton *resizeBtn;
  32. @end
  33. @implementation AMShipMap
  34. - (void)handleLoaction:(NSDictionary *)location Priority:(AMShipAnnotationPriority)priority ImageName:(NSString *)imgName {
  35. if (location == nil) {
  36. return;
  37. }
  38. NSString *port = [location valueForKey:@"port"];
  39. NSString* addr = [location valueForKey:@"addr"];
  40. NSString* name = [location valueForKey:@"name"];
  41. NSString *lonStr = [location valueForKey:@"lon"];
  42. NSString *latStr = [location valueForKey:@"lat"];
  43. if (lonStr && lonStr.length > 0 && latStr && latStr.length > 0) {
  44. double longitude = [lonStr doubleValue];
  45. double latitude = [latStr doubleValue];
  46. if (port == nil) {
  47. port = @"";
  48. }
  49. if (addr == nil) {
  50. addr = @"";
  51. }
  52. // 创建大头针(标注)的数据模型(此处不创建视图,视图通过MKMapView的委托设置回调方法来生成的)
  53. AMShipAnnotation *ann = [[AMShipAnnotation alloc] init];
  54. CLLocationCoordinate2D c2d = CLLocationCoordinate2DMake(latitude, longitude);
  55. // 指定大头针的经纬度坐标(位置)以及附加的信息
  56. ann.coordinate = c2d;
  57. ann.title = name;
  58. ann.subtitle = [NSString stringWithFormat:@"%@ %@",port,addr];
  59. ann.priority = priority;
  60. ann.imageName = imgName;
  61. if ([port isEqualToString:@"Current"]) {
  62. ann.isCurrent = YES;
  63. }
  64. // 将大头针数据模型添加到MKMapView上管理
  65. [self.mapView addAnnotation:ann];
  66. } else {
  67. return;
  68. }
  69. }
  70. - (void)moveToLocation:(NSDictionary *)location {
  71. if (location == nil) {
  72. return;
  73. }
  74. NSString *lonStr = [location valueForKey:@"lon"];
  75. NSString *latStr = [location valueForKey:@"lat"];
  76. if (lonStr && lonStr.length > 0 && latStr && latStr.length > 0) {
  77. double longitude = [lonStr doubleValue];
  78. double latitude = [latStr doubleValue];
  79. CLLocationCoordinate2D c2d = CLLocationCoordinate2DMake(latitude, longitude);
  80. MKCoordinateSpan span = MKCoordinateSpanMake(180, 360);
  81. // 创建一个区域结构体变量
  82. MKCoordinateRegion region = MKCoordinateRegionMake(c2d, span);
  83. // 将大头针数据模型添加到MKMapView上管理
  84. [self.mapView setRegion:region animated:YES];
  85. }
  86. }
  87. - (void)showShipAnnotaion:(NSDictionary *)annotation backupLocation:(NSString*)port{
  88. if (annotation == nil) {
  89. return;
  90. }
  91. [self.mapView removeAnnotations:self.mapView.annotations];
  92. NSDictionary *locationInfo = annotation;
  93. if (_currentAnnotaion) {
  94. // [self stopTwinkle];
  95. _currentAnnotaion.alpha = 1.f;
  96. _currentAnnotaion = nil;
  97. }
  98. // pol,pod,poe,por,origin,destination,current
  99. if (locationInfo) {
  100. NSMutableDictionary *pol = [[locationInfo objectForKey:@"pol"] mutableCopy];
  101. if (self.showPol) {
  102. [pol setObject:@"Port Of Load" forKey:@"port"];
  103. [self handleLoaction:pol Priority:AMShipAnnotationPriorityHigh ImageName:@"new_location_pol"];
  104. }
  105. NSMutableDictionary *pod = [[locationInfo objectForKey:@"pod"] mutableCopy];
  106. if (self.showPod) {
  107. [pod setObject:@"Port Of Discharge" forKey:@"port"];
  108. [self handleLoaction:pod Priority:AMShipAnnotationPriorityHigh ImageName:@"new_location_pod"];
  109. }
  110. NSMutableDictionary *poe = [[locationInfo objectForKey:@"poe"] mutableCopy];
  111. if (self.showPoe) {
  112. [poe setObject:@"Place Of Deliver" forKey:@"port"];
  113. [self handleLoaction:poe Priority:AMShipAnnotationPriorityLow ImageName:@"new_location_poe"];
  114. }
  115. NSMutableDictionary *por = [[locationInfo objectForKey:@"por"] mutableCopy];
  116. if (self.showPor) {
  117. [por setObject:@"Place Of Receipt" forKey:@"port"];
  118. [self handleLoaction:por Priority:AMShipAnnotationPriorityLow ImageName:@"new_location_por"];
  119. }
  120. NSMutableDictionary *origin = [[locationInfo objectForKey:@"origin"] mutableCopy];
  121. if (self.showOrigin) {
  122. [origin setObject:@"Origin" forKey:@"port"];
  123. [self handleLoaction:origin Priority:AMShipAnnotationPriorityLow ImageName:@"new_location_origin"];
  124. }
  125. NSMutableDictionary *destination = [[locationInfo objectForKey:@"destination"] mutableCopy];
  126. if (self.showDestination) {
  127. [destination setObject:@"Destination" forKey:@"port"];
  128. [self handleLoaction:destination Priority:AMShipAnnotationPriorityLow ImageName:@"new_location_destination"];
  129. }
  130. NSMutableDictionary *current = [[locationInfo objectForKey:@"current"] mutableCopy];
  131. if (self.showCurrent) {
  132. [current setObject:@"Current" forKey:@"port"];
  133. [self handleLoaction:current Priority:AMShipAnnotationPriorityRequired ImageName:@"ic_marker"];
  134. }
  135. if (current && self.showCurrent) {
  136. [self moveToLocation:current];
  137. } else if ([port isEqualToString:@"pol"]&& pol && self.showPol) {
  138. [self moveToLocation:pol];
  139. } else if ([port isEqualToString:@"pod"]&&pod && self.showPod) {
  140. [self moveToLocation:pod];
  141. }
  142. }
  143. // [self startTwinkle];
  144. }
  145. #pragma mark - Twinkle Current
  146. - (void)startTwinkle {
  147. if (_twinkleTimer) {
  148. return;
  149. }
  150. __weak typeof(self) weakSelf = self;
  151. dispatch_async(dispatch_get_global_queue(0, 0), ^{
  152. if (weakSelf) {
  153. __strong typeof(weakSelf) strongSelf = weakSelf;
  154. strongSelf->_twinkleTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(twinkleTimerExecute:) userInfo:nil repeats:YES];
  155. [[NSRunLoop currentRunLoop] addTimer:strongSelf->_twinkleTimer forMode:NSDefaultRunLoopMode];
  156. [[NSRunLoop currentRunLoop] run];
  157. }
  158. });
  159. }
  160. - (void)twinkleTimerExecute:(NSTimer *)timer {
  161. if (!_currentAnnotaion) {
  162. return;
  163. }
  164. __weak typeof(self) weakSelf = self;
  165. dispatch_async(dispatch_get_main_queue(), ^{
  166. if (weakSelf) {
  167. __strong typeof(weakSelf) strongSelf = weakSelf;
  168. strongSelf->_timerAngle += 0.1;
  169. if (strongSelf->_timerAngle == 3.1) {
  170. strongSelf->_timerAngle = 0;
  171. }
  172. float alpha = ABS(cos(strongSelf->_timerAngle));
  173. strongSelf->_currentAnnotaion.alpha = alpha;
  174. }
  175. });
  176. }
  177. - (void)stopTwinkle {
  178. if (_twinkleTimer) {
  179. [_twinkleTimer invalidate];
  180. _twinkleTimer = nil;
  181. }
  182. }
  183. #pragma mark - Apear
  184. - (void)shipMapWillAppear {
  185. if (self.twinkleCurrent) {
  186. [self startTwinkle];
  187. }
  188. }
  189. - (void)shipMapWillDisappear {
  190. [self stopTwinkle];
  191. }
  192. #pragma mark - Map Delegate
  193. // 当地图上添加了标注以后要执行的回调方法
  194. - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
  195. if ([annotation isKindOfClass:[AMShipAnnotation class]]) {
  196. // 获取可复用的大头针视图
  197. AMAnnotationView *pinView = (id)[mapView dequeueReusableAnnotationViewWithIdentifier:@"PIN"];
  198. if (!pinView) { // 如果没有可重用的大头针视图就创建并指定重用标识
  199. pinView = [[AMAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"PIN"];
  200. }
  201. AMShipAnnotation *shipAnnotation = (AMShipAnnotation *)annotation;
  202. if (shipAnnotation.imageName) {
  203. pinView.image = [UIImage imageNamed:shipAnnotation.imageName];
  204. } else {
  205. pinView.image = [UIImage imageNamed:@"ic_marker"];
  206. }
  207. if (@available(iOS 11,*)) {
  208. if (shipAnnotation.priority == AMShipAnnotationPriorityRequired) {
  209. pinView.displayPriority = MKFeatureDisplayPriorityRequired;
  210. } else if (shipAnnotation.priority == AMShipAnnotationPriorityHigh) {
  211. pinView.displayPriority = MKFeatureDisplayPriorityDefaultHigh;
  212. } else {
  213. pinView.displayPriority = MKFeatureDisplayPriorityDefaultLow;
  214. }
  215. }
  216. if (shipAnnotation.isCurrent) {
  217. _currentAnnotaion = pinView;
  218. }
  219. return pinView;
  220. } else {
  221. return nil;
  222. }
  223. // return nil;
  224. }
  225. #pragma mark - Action
  226. - (void)resizeButtonClick:(UIButton *)sender {
  227. sender.selected = !sender.selected;
  228. if (self.delegate && [self.delegate respondsToSelector:@selector(shipMap:tryToZoomIn:)]) {
  229. [self.delegate shipMap:self tryToZoomIn:sender.selected];
  230. }
  231. }
  232. #pragma mark - Setter
  233. - (void)setShowZoomControl:(BOOL)showZoomControl {
  234. _showZoomControl = showZoomControl;
  235. self.resizeBtn.hidden = !_showZoomControl;
  236. }
  237. #pragma mark - Life
  238. - (void)dealloc {
  239. [self stopTwinkle];
  240. }
  241. - (void)setup {
  242. [self setupMap];
  243. self.resizeBtn = [UIButton buttonWithType:UIButtonTypeCustom];
  244. [self.resizeBtn setImage:[UIImage imageNamed:@"resize_max"] forState:UIControlStateNormal];
  245. [self.resizeBtn setImage:[UIImage imageNamed:@"resize_min"] forState:UIControlStateSelected];
  246. [self.resizeBtn addTarget:self action:@selector(resizeButtonClick:) forControlEvents:UIControlEventTouchUpInside];
  247. self.resizeBtn.translatesAutoresizingMaskIntoConstraints = NO;
  248. [self addSubview:self.resizeBtn];
  249. NSLayoutConstraint *top = [NSLayoutConstraint constraintWithItem:self.resizeBtn
  250. attribute:NSLayoutAttributeTop
  251. relatedBy:NSLayoutRelationEqual
  252. toItem:self
  253. attribute:NSLayoutAttributeTop
  254. multiplier:1.0
  255. constant:10];
  256. NSLayoutConstraint *right = [NSLayoutConstraint constraintWithItem:self.resizeBtn
  257. attribute:NSLayoutAttributeRight
  258. relatedBy:NSLayoutRelationEqual
  259. toItem:self
  260. attribute:NSLayoutAttributeRight
  261. multiplier:1.0
  262. constant:-10];
  263. [self addConstraints:@[top,right]];
  264. [self layoutIfNeeded];
  265. self.showPol = YES;
  266. self.showPod = YES;
  267. self.showCurrent = YES;
  268. self.showZoomControl = YES;
  269. self.twinkleCurrent = YES;
  270. }
  271. - (void)setupMap {
  272. self.mapView = [[AMMapView alloc] init];
  273. self.mapView.delegate = self;
  274. self.mapView.translatesAutoresizingMaskIntoConstraints = NO;
  275. [self addSubview:self.mapView];
  276. self.mapView.rotateEnabled = NO;
  277. // 显示比例尺
  278. self.mapView.showsScale = YES;
  279. // 显示用户的位置
  280. // self.mapView.showsUserLocation = YES;
  281. NSLayoutConstraint *top = [NSLayoutConstraint constraintWithItem:self.mapView
  282. attribute:NSLayoutAttributeTop
  283. relatedBy:NSLayoutRelationEqual
  284. toItem:self
  285. attribute:NSLayoutAttributeTop
  286. multiplier:1.0
  287. constant:0];
  288. NSLayoutConstraint *left = [NSLayoutConstraint constraintWithItem:self.mapView
  289. attribute:NSLayoutAttributeLeft
  290. relatedBy:NSLayoutRelationEqual
  291. toItem:self
  292. attribute:NSLayoutAttributeLeft
  293. multiplier:1.0
  294. constant:0];
  295. NSLayoutConstraint *bottom = [NSLayoutConstraint constraintWithItem:self.mapView
  296. attribute:NSLayoutAttributeBottom
  297. relatedBy:NSLayoutRelationEqual
  298. toItem:self
  299. attribute:NSLayoutAttributeBottom
  300. multiplier:1.0
  301. constant:0];
  302. NSLayoutConstraint *right = [NSLayoutConstraint constraintWithItem:self.mapView
  303. attribute:NSLayoutAttributeRight
  304. relatedBy:NSLayoutRelationEqual
  305. toItem:self
  306. attribute:NSLayoutAttributeRight
  307. multiplier:1.0
  308. constant:0];
  309. [self addConstraints:@[top,left,bottom,right]];
  310. }
  311. - (instancetype)init {
  312. if (self = [super init]) {
  313. [self setup];
  314. }
  315. return self;
  316. }
  317. - (instancetype)initWithCoder:(NSCoder *)aDecoder {
  318. if (self = [super initWithCoder:aDecoder]) {
  319. [self setup];
  320. }
  321. return self;
  322. }
  323. - (instancetype)initWithFrame:(CGRect)frame {
  324. if (self = [super initWithFrame:frame]) {
  325. [self setup];
  326. }
  327. return self;
  328. }
  329. @end