ApexMapView.m 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. //
  2. // ApexMapView.m
  3. // OpenStreetMap
  4. //
  5. // Created by Jack on 2019/1/18.
  6. // Copyright © 2019 Jack Template. All rights reserved.
  7. //
  8. #import "ApexMapView.h"
  9. #import "UIView+RAConstraint.h"
  10. //static NSString * const kTileSource = @"https://map.apexshipping.com/osm_tiles/{z}/{x}/{y}.png";
  11. //static NSString * const kTileSource = @"https://map.apexshipping.com/osmmt/{z}/{x}/{y}.png";
  12. static NSString * const kTileSource = @"https://map.apexshipping.com/osmhd/{z}/{x}/{y}.png";
  13. static int const tileSize = 512;
  14. static NSString * const kOpenStreetMapURL = @"https://www.openstreetmap.org/copyright";
  15. static NSString * const kCopyright = @"OpenStreetMap";
  16. @interface ApexMapView () <MKMapViewDelegate>
  17. @property (nonatomic,strong) UIButton *legalBtn;
  18. @property (nonatomic,strong) MKTileOverlay *tileOverlay;
  19. @property (nonatomic,weak) id<MKMapViewDelegate> internalDelegate;
  20. @end
  21. @implementation ApexMapView
  22. #pragma mark - Initial
  23. - (instancetype)initWithFrame:(CGRect)frame {
  24. if (self = [super initWithFrame:frame]) {
  25. [self setupMapView];
  26. }
  27. return self;
  28. }
  29. - (void)awakeFromNib {
  30. [super awakeFromNib];
  31. [self setupMapView];
  32. }
  33. - (void)setupMapView {
  34. self.rotateEnabled = NO;
  35. [self apex_setDelegate:self];
  36. [self addOverlay:self.tileOverlay];
  37. // if (@available(iOS 13.0, *)) {
  38. // MKMapCameraZoomRange* zoom_range =[[MKMapCameraZoomRange alloc] initWithMinCenterCoordinateDistance:500];
  39. // // [[MKMapCameraZoomRange alloc] initWithMinCenterCoordinateDistance:-1 maxCenterCoordinateDistance:10];
  40. // [self setCameraZoomRange:zoom_range];
  41. // } else {
  42. // // Fallback on earlier versions
  43. // }
  44. }
  45. - (void)layoutSubviews {
  46. [super layoutSubviews];
  47. NSArray<UIView *> *subViews = self.subviews;
  48. for (UIView *subView in subViews) {
  49. if ([subView isMemberOfClass:NSClassFromString(@"MKAttributionLabel")]) {
  50. [subView removeFromSuperview];
  51. } else if ([subView isMemberOfClass:[UIImageView class]]) {
  52. [subView removeFromSuperview];
  53. }
  54. }
  55. if (![subViews containsObject:self.legalBtn]) {
  56. [self setupLegalView];
  57. }
  58. }
  59. - (void)setupLegalView {
  60. [self addSubview:self.legalBtn];
  61. [self.legalBtn ra_applyConstraints:^(RAConstraintMaker *maker) {
  62. maker.left.ra_equalTo(self.left).ra_offset(5.0f);
  63. maker.bottom.ra_equalTo(self.bottom).ra_offset(-5.0f);
  64. }];
  65. }
  66. #pragma mark - Override
  67. - (void)setDelegate:(id<MKMapViewDelegate>)delegate {
  68. if (delegate) {
  69. __weak typeof(delegate) weakDelegate = delegate;
  70. _internalDelegate = weakDelegate;
  71. } else {
  72. _internalDelegate = nil;
  73. }
  74. }
  75. - (void)apex_setDelegate:(id<MKMapViewDelegate>)delegate {
  76. [super setDelegate:delegate];
  77. }
  78. #pragma mark - Getter
  79. //- (double) zoomLevel {
  80. //
  81. ////
  82. //// double d= 360 * self.frame.size.width /256/self.region.span.longitudeDelta;
  83. //// return log2(d);
  84. ////
  85. // MKCoordinateRegion region = self.region;
  86. //
  87. // double centerPixelX = [MKMapView longitudeToPixelSpaceX: region.center.longitude];
  88. // double topLeftPixelX = [MKMapView longitudeToPixelSpaceX: region.center.longitude - region.span.longitudeDelta / 2];
  89. //
  90. // double scaledMapWidth = (centerPixelX - topLeftPixelX) * 2;
  91. // CGSize mapSizeInPixels = self.bounds.size;
  92. // double zoomScale = scaledMapWidth / mapSizeInPixels.width;
  93. // double zoomExponent = log(zoomScale/(512/256)) / log(2);
  94. // double zoomLevel = 20 - zoomExponent;
  95. //
  96. // return zoomLevel;
  97. //}
  98. - (MKTileOverlay *)tileOverlay {
  99. if (!_tileOverlay) {
  100. _tileOverlay = [[MKTileOverlay alloc] initWithURLTemplate:kTileSource];
  101. _tileOverlay.canReplaceMapContent = YES;
  102. _tileOverlay.minimumZ = 0;
  103. _tileOverlay.maximumZ = 18;
  104. _tileOverlay.tileSize = CGSizeMake(tileSize, tileSize);
  105. }
  106. return _tileOverlay;
  107. }
  108. - (UIButton *)legalBtn {
  109. if (!_legalBtn) {
  110. _legalBtn = [UIButton buttonWithType:UIButtonTypeSystem];
  111. _legalBtn.titleLabel.font = [UIFont systemFontOfSize:12.0f];
  112. [_legalBtn setTitle:kCopyright forState:UIControlStateNormal];
  113. [_legalBtn addTarget:self action:@selector(legalButtonDidClick:) forControlEvents:UIControlEventTouchUpInside];
  114. }
  115. return _legalBtn;
  116. }
  117. #pragma mark - User Action
  118. - (void)legalButtonDidClick:(id)sender {
  119. NSURL *url = [NSURL URLWithString:kOpenStreetMapURL];
  120. if ([[UIApplication sharedApplication] canOpenURL:url]) {
  121. if (@available(iOS 10, *)) {
  122. [[UIApplication sharedApplication] openURL:url options:@{UIApplicationOpenURLOptionsSourceApplicationKey: @YES} completionHandler:^(BOOL success) {
  123. }];
  124. } else{
  125. [[UIApplication sharedApplication] openURL:url];
  126. }
  127. }
  128. }
  129. #pragma mark - MKMapViewDelegate
  130. - (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated {
  131. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:regionWillChangeAnimated:)]) {
  132. [_internalDelegate mapView:mapView regionWillChangeAnimated:animated];
  133. }
  134. }
  135. - (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
  136. double z=[self zoomLevel];
  137. double pi =3.1415926;
  138. int x= floor((mapView.centerCoordinate.longitude + 180) / 360 * pow(2 , z));
  139. int y= floor((1 - log(tan(mapView.centerCoordinate.latitude * pi / 180) + 1 / cos(mapView.centerCoordinate.latitude * pi / 180)) / pi) / 2 * pow(2 , z));
  140. NSLog(@"地图控件完成了改变 x:%d,y:%d,z:%f",x,y,z);
  141. if(mapView.zoomLevel>18)
  142. {
  143. NSLog(@"地图控件完成了改变 zoom to 18");
  144. [mapView setCenterCoordinate:mapView.centerCoordinate zoomLevel:18 animated:true];
  145. }
  146. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:regionDidChangeAnimated:)]) {
  147. [_internalDelegate mapView:mapView regionDidChangeAnimated:animated];
  148. }
  149. }
  150. - (void)mapViewDidChangeVisibleRegion:(MKMapView *)mapView {
  151. // double z=[self zoomLevel];
  152. //
  153. // double pi =3.1415926;
  154. // int x= floor((mapView.centerCoordinate.longitude + 180) / 360 * pow(2 , z));
  155. //
  156. // int y= floor((1 - log(tan(mapView.centerCoordinate.latitude * pi / 180) + 1 / cos(mapView.centerCoordinate.latitude * pi / 180)) / pi) / 2 * pow(2 , z));
  157. //
  158. // NSLog(@"地图控件完成了改变 x:%d,y:%d,z:%f",x,y,z);
  159. //
  160. // if((int)z>18)
  161. // {
  162. //
  163. //
  164. // [mapView setCenterCoordinate:mapView.centerCoordinate zoomLevel:18 animated:true];
  165. //
  166. // }
  167. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapViewDidChangeVisibleRegion:)]) {
  168. [_internalDelegate mapViewDidChangeVisibleRegion:mapView];
  169. }
  170. }
  171. - (void)mapViewWillStartLoadingMap:(MKMapView *)mapView {
  172. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapViewWillStartLoadingMap:)]) {
  173. [_internalDelegate mapViewWillStartLoadingMap:mapView];
  174. }
  175. }
  176. - (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView {
  177. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapViewDidFinishLoadingMap:)]) {
  178. [_internalDelegate mapViewDidFinishLoadingMap:mapView];
  179. }
  180. }
  181. - (void)mapViewDidFailLoadingMap:(MKMapView *)mapView withError:(NSError *)error {
  182. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapViewDidFailLoadingMap:withError:)]) {
  183. [_internalDelegate mapViewDidFailLoadingMap:mapView withError:error];
  184. }
  185. }
  186. - (void)mapViewWillStartRenderingMap:(MKMapView *)mapView {
  187. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapViewWillStartRenderingMap:)]) {
  188. [_internalDelegate mapViewWillStartRenderingMap:mapView];
  189. }
  190. }
  191. - (void)mapViewDidFinishRenderingMap:(MKMapView *)mapView fullyRendered:(BOOL)fullyRendered {
  192. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapViewDidFinishRenderingMap:fullyRendered:)]) {
  193. [_internalDelegate mapViewDidFinishRenderingMap:mapView fullyRendered:fullyRendered];
  194. }
  195. }
  196. // mapView:viewForAnnotation: provides the view for each annotation.
  197. // This method may be called for all or some of the added annotations.
  198. // For MapKit provided annotations (eg. MKUserLocation) return nil to use the MapKit provided annotation view.
  199. - (nullable MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
  200. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:viewForAnnotation:)]) {
  201. return [_internalDelegate mapView:mapView viewForAnnotation:annotation];
  202. }
  203. return nil;
  204. }
  205. // mapView:didAddAnnotationViews: is called after the annotation views have been added and positioned in the map.
  206. // The delegate can implement this method to animate the adding of the annotations views.
  207. // Use the current positions of the annotation views as the destinations of the animation.
  208. - (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray<MKAnnotationView *> *)views {
  209. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:didAddAnnotationViews:)]) {
  210. [_internalDelegate mapView:mapView didAddAnnotationViews:views];
  211. }
  212. }
  213. #if TARGET_OS_IPHONE
  214. // mapView:annotationView:calloutAccessoryControlTapped: is called when the user taps on left & right callout accessory UIControls.
  215. - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
  216. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:annotationView:calloutAccessoryControlTapped:)]) {
  217. [_internalDelegate mapView:mapView annotationView:view calloutAccessoryControlTapped:control];
  218. }
  219. }
  220. #endif
  221. - (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view {
  222. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:didSelectAnnotationView:)]) {
  223. [_internalDelegate mapView:mapView didSelectAnnotationView:view];
  224. }
  225. }
  226. - (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view {
  227. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:didDeselectAnnotationView:)]) {
  228. [_internalDelegate mapView:mapView didDeselectAnnotationView:view];
  229. }
  230. }
  231. - (void)mapViewWillStartLocatingUser:(MKMapView *)mapView {
  232. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapViewWillStartLocatingUser:)]) {
  233. [_internalDelegate mapViewWillStartLocatingUser:mapView];
  234. }
  235. }
  236. - (void)mapViewDidStopLocatingUser:(MKMapView *)mapView {
  237. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapViewDidStopLocatingUser:)]) {
  238. [_internalDelegate mapViewDidStopLocatingUser:mapView];
  239. }
  240. }
  241. - (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation {
  242. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:didUpdateUserLocation:)]) {
  243. [_internalDelegate mapView:mapView didUpdateUserLocation:userLocation];
  244. }
  245. }
  246. - (void)mapView:(MKMapView *)mapView didFailToLocateUserWithError:(NSError *)error {
  247. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:didFailToLocateUserWithError:)]) {
  248. [_internalDelegate mapView:mapView didFailToLocateUserWithError:error];
  249. }
  250. }
  251. - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view didChangeDragState:(MKAnnotationViewDragState)newState
  252. fromOldState:(MKAnnotationViewDragState)oldState {
  253. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:annotationView:didChangeDragState:fromOldState:)]) {
  254. [_internalDelegate mapView:mapView annotationView:view didChangeDragState:newState fromOldState:oldState];
  255. }
  256. }
  257. #if TARGET_OS_IPHONE
  258. - (void)mapView:(MKMapView *)mapView didChangeUserTrackingMode:(MKUserTrackingMode)mode animated:(BOOL)animated {
  259. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:didChangeUserTrackingMode:animated:)]) {
  260. [_internalDelegate mapView:mapView didChangeUserTrackingMode:mode animated:animated];
  261. }
  262. }
  263. #endif
  264. - (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id <MKOverlay>)overlay {
  265. if (overlay == self.tileOverlay) {
  266. return [[MKTileOverlayRenderer alloc] initWithTileOverlay:overlay];
  267. } else {
  268. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:rendererForOverlay:)]) {
  269. return [_internalDelegate mapView:mapView rendererForOverlay:overlay];
  270. } else {
  271. return nil;
  272. }
  273. }
  274. }
  275. - (void)mapView:(MKMapView *)mapView didAddOverlayRenderers:(NSArray<MKOverlayRenderer *> *)renderers {
  276. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:didAddOverlayRenderers:)]) {
  277. [_internalDelegate mapView:mapView didAddOverlayRenderers:renderers];
  278. }
  279. }
  280. #if TARGET_OS_IPHONE
  281. // Prefer -mapView:rendererForOverlay:
  282. - (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay {
  283. if (overlay == self.tileOverlay) {
  284. return [[MKOverlayView alloc] initWithOverlay:overlay];
  285. } else {
  286. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:viewForOverlay:)]) {
  287. return [_internalDelegate mapView:mapView viewForOverlay:overlay];
  288. } else {
  289. return nil;
  290. }
  291. }
  292. }
  293. // Called after the provided overlay views have been added and positioned in the map.
  294. // Prefer -mapView:didAddOverlayRenderers:
  295. - (void)mapView:(MKMapView *)mapView didAddOverlayViews:(NSArray *)overlayViews {
  296. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:didAddOverlayViews:)]) {
  297. [_internalDelegate mapView:mapView didAddOverlayViews:overlayViews];
  298. }
  299. }
  300. #endif
  301. // Return nil for default MKClusterAnnotation, it is illegal to return a cluster annotation not containing the identical array of member annotations given.
  302. - (MKClusterAnnotation *)mapView:(MKMapView *)mapView clusterAnnotationForMemberAnnotations:(NSArray<id<MKAnnotation>>*)memberAnnotations {
  303. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:clusterAnnotationForMemberAnnotations:)]) {
  304. return [_internalDelegate mapView:mapView clusterAnnotationForMemberAnnotations:memberAnnotations];
  305. }
  306. return nil;
  307. }
  308. @end