ApexMapView.m 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  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. }
  38. - (void)layoutSubviews {
  39. [super layoutSubviews];
  40. NSArray<UIView *> *subViews = self.subviews;
  41. for (UIView *subView in subViews) {
  42. if ([subView isMemberOfClass:NSClassFromString(@"MKAttributionLabel")]) {
  43. [subView removeFromSuperview];
  44. } else if ([subView isMemberOfClass:[UIImageView class]]) {
  45. [subView removeFromSuperview];
  46. }
  47. }
  48. if (![subViews containsObject:self.legalBtn]) {
  49. [self setupLegalView];
  50. }
  51. }
  52. - (void)setupLegalView {
  53. [self addSubview:self.legalBtn];
  54. [self.legalBtn ra_applyConstraints:^(RAConstraintMaker *maker) {
  55. maker.left.ra_equalTo(self.left).ra_offset(5.0f);
  56. maker.bottom.ra_equalTo(self.bottom).ra_offset(-5.0f);
  57. }];
  58. }
  59. #pragma mark - Override
  60. - (void)setDelegate:(id<MKMapViewDelegate>)delegate {
  61. if (delegate) {
  62. __weak typeof(delegate) weakDelegate = delegate;
  63. _internalDelegate = weakDelegate;
  64. } else {
  65. _internalDelegate = nil;
  66. }
  67. }
  68. - (void)apex_setDelegate:(id<MKMapViewDelegate>)delegate {
  69. [super setDelegate:delegate];
  70. }
  71. #pragma mark - Getter
  72. - (MKTileOverlay *)tileOverlay {
  73. if (!_tileOverlay) {
  74. _tileOverlay = [[MKTileOverlay alloc] initWithURLTemplate:kTileSource];
  75. _tileOverlay.canReplaceMapContent = YES;
  76. _tileOverlay.minimumZ = 1;
  77. _tileOverlay.maximumZ = 18;
  78. _tileOverlay.tileSize = CGSizeMake(tileSize, tileSize);
  79. }
  80. return _tileOverlay;
  81. }
  82. - (UIButton *)legalBtn {
  83. if (!_legalBtn) {
  84. _legalBtn = [UIButton buttonWithType:UIButtonTypeSystem];
  85. _legalBtn.titleLabel.font = [UIFont systemFontOfSize:12.0f];
  86. [_legalBtn setTitle:kCopyright forState:UIControlStateNormal];
  87. [_legalBtn addTarget:self action:@selector(legalButtonDidClick:) forControlEvents:UIControlEventTouchUpInside];
  88. }
  89. return _legalBtn;
  90. }
  91. #pragma mark - User Action
  92. - (void)legalButtonDidClick:(id)sender {
  93. NSURL *url = [NSURL URLWithString:kOpenStreetMapURL];
  94. if ([[UIApplication sharedApplication] canOpenURL:url]) {
  95. if (@available(iOS 10, *)) {
  96. [[UIApplication sharedApplication] openURL:url options:@{UIApplicationOpenURLOptionsSourceApplicationKey: @YES} completionHandler:^(BOOL success) {
  97. }];
  98. } else{
  99. [[UIApplication sharedApplication] openURL:url];
  100. }
  101. }
  102. }
  103. #pragma mark - MKMapViewDelegate
  104. - (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated {
  105. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:regionWillChangeAnimated:)]) {
  106. [_internalDelegate mapView:mapView regionWillChangeAnimated:animated];
  107. }
  108. }
  109. - (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
  110. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:regionDidChangeAnimated:)]) {
  111. [_internalDelegate mapView:mapView regionDidChangeAnimated:animated];
  112. }
  113. }
  114. - (void)mapViewDidChangeVisibleRegion:(MKMapView *)mapView {
  115. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapViewDidChangeVisibleRegion:)]) {
  116. [_internalDelegate mapViewDidChangeVisibleRegion:mapView];
  117. }
  118. }
  119. - (void)mapViewWillStartLoadingMap:(MKMapView *)mapView {
  120. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapViewWillStartLoadingMap:)]) {
  121. [_internalDelegate mapViewWillStartLoadingMap:mapView];
  122. }
  123. }
  124. - (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView {
  125. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapViewDidFinishLoadingMap:)]) {
  126. [_internalDelegate mapViewDidFinishLoadingMap:mapView];
  127. }
  128. }
  129. - (void)mapViewDidFailLoadingMap:(MKMapView *)mapView withError:(NSError *)error {
  130. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapViewDidFailLoadingMap:withError:)]) {
  131. [_internalDelegate mapViewDidFailLoadingMap:mapView withError:error];
  132. }
  133. }
  134. - (void)mapViewWillStartRenderingMap:(MKMapView *)mapView {
  135. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapViewWillStartRenderingMap:)]) {
  136. [_internalDelegate mapViewWillStartRenderingMap:mapView];
  137. }
  138. }
  139. - (void)mapViewDidFinishRenderingMap:(MKMapView *)mapView fullyRendered:(BOOL)fullyRendered {
  140. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapViewDidFinishRenderingMap:fullyRendered:)]) {
  141. [_internalDelegate mapViewDidFinishRenderingMap:mapView fullyRendered:fullyRendered];
  142. }
  143. }
  144. // mapView:viewForAnnotation: provides the view for each annotation.
  145. // This method may be called for all or some of the added annotations.
  146. // For MapKit provided annotations (eg. MKUserLocation) return nil to use the MapKit provided annotation view.
  147. - (nullable MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
  148. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:viewForAnnotation:)]) {
  149. return [_internalDelegate mapView:mapView viewForAnnotation:annotation];
  150. }
  151. return nil;
  152. }
  153. // mapView:didAddAnnotationViews: is called after the annotation views have been added and positioned in the map.
  154. // The delegate can implement this method to animate the adding of the annotations views.
  155. // Use the current positions of the annotation views as the destinations of the animation.
  156. - (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray<MKAnnotationView *> *)views {
  157. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:didAddAnnotationViews:)]) {
  158. [_internalDelegate mapView:mapView didAddAnnotationViews:views];
  159. }
  160. }
  161. #if TARGET_OS_IPHONE
  162. // mapView:annotationView:calloutAccessoryControlTapped: is called when the user taps on left & right callout accessory UIControls.
  163. - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
  164. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:annotationView:calloutAccessoryControlTapped:)]) {
  165. [_internalDelegate mapView:mapView annotationView:view calloutAccessoryControlTapped:control];
  166. }
  167. }
  168. #endif
  169. - (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view {
  170. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:didSelectAnnotationView:)]) {
  171. [_internalDelegate mapView:mapView didSelectAnnotationView:view];
  172. }
  173. }
  174. - (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view {
  175. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:didDeselectAnnotationView:)]) {
  176. [_internalDelegate mapView:mapView didDeselectAnnotationView:view];
  177. }
  178. }
  179. - (void)mapViewWillStartLocatingUser:(MKMapView *)mapView {
  180. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapViewWillStartLocatingUser:)]) {
  181. [_internalDelegate mapViewWillStartLocatingUser:mapView];
  182. }
  183. }
  184. - (void)mapViewDidStopLocatingUser:(MKMapView *)mapView {
  185. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapViewDidStopLocatingUser:)]) {
  186. [_internalDelegate mapViewDidStopLocatingUser:mapView];
  187. }
  188. }
  189. - (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation {
  190. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:didUpdateUserLocation:)]) {
  191. [_internalDelegate mapView:mapView didUpdateUserLocation:userLocation];
  192. }
  193. }
  194. - (void)mapView:(MKMapView *)mapView didFailToLocateUserWithError:(NSError *)error {
  195. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:didFailToLocateUserWithError:)]) {
  196. [_internalDelegate mapView:mapView didFailToLocateUserWithError:error];
  197. }
  198. }
  199. - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view didChangeDragState:(MKAnnotationViewDragState)newState
  200. fromOldState:(MKAnnotationViewDragState)oldState {
  201. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:annotationView:didChangeDragState:fromOldState:)]) {
  202. [_internalDelegate mapView:mapView annotationView:view didChangeDragState:newState fromOldState:oldState];
  203. }
  204. }
  205. #if TARGET_OS_IPHONE
  206. - (void)mapView:(MKMapView *)mapView didChangeUserTrackingMode:(MKUserTrackingMode)mode animated:(BOOL)animated {
  207. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:didChangeUserTrackingMode:animated:)]) {
  208. [_internalDelegate mapView:mapView didChangeUserTrackingMode:mode animated:animated];
  209. }
  210. }
  211. #endif
  212. - (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id <MKOverlay>)overlay {
  213. if (overlay == self.tileOverlay) {
  214. return [[MKTileOverlayRenderer alloc] initWithTileOverlay:overlay];
  215. } else {
  216. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:rendererForOverlay:)]) {
  217. return [_internalDelegate mapView:mapView rendererForOverlay:overlay];
  218. } else {
  219. return nil;
  220. }
  221. }
  222. }
  223. - (void)mapView:(MKMapView *)mapView didAddOverlayRenderers:(NSArray<MKOverlayRenderer *> *)renderers {
  224. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:didAddOverlayRenderers:)]) {
  225. [_internalDelegate mapView:mapView didAddOverlayRenderers:renderers];
  226. }
  227. }
  228. #if TARGET_OS_IPHONE
  229. // Prefer -mapView:rendererForOverlay:
  230. - (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay {
  231. if (overlay == self.tileOverlay) {
  232. return [[MKOverlayView alloc] initWithOverlay:overlay];
  233. } else {
  234. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:viewForOverlay:)]) {
  235. return [_internalDelegate mapView:mapView viewForOverlay:overlay];
  236. } else {
  237. return nil;
  238. }
  239. }
  240. }
  241. // Called after the provided overlay views have been added and positioned in the map.
  242. // Prefer -mapView:didAddOverlayRenderers:
  243. - (void)mapView:(MKMapView *)mapView didAddOverlayViews:(NSArray *)overlayViews {
  244. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:didAddOverlayViews:)]) {
  245. [_internalDelegate mapView:mapView didAddOverlayViews:overlayViews];
  246. }
  247. }
  248. #endif
  249. // Return nil for default MKClusterAnnotation, it is illegal to return a cluster annotation not containing the identical array of member annotations given.
  250. - (MKClusterAnnotation *)mapView:(MKMapView *)mapView clusterAnnotationForMemberAnnotations:(NSArray<id<MKAnnotation>>*)memberAnnotations {
  251. if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:clusterAnnotationForMemberAnnotations:)]) {
  252. return [_internalDelegate mapView:mapView clusterAnnotationForMemberAnnotations:memberAnnotations];
  253. }
  254. return nil;
  255. }
  256. @end