ApexMapView.m 15 KB

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