فهرست منبع

1.封装iOS OpenStreetMap。

Pen Li 7 سال پیش
والد
کامیت
ad3d21cd79
2فایلهای تغییر یافته به همراه347 افزوده شده و 0 حذف شده
  1. 15 0
      common/ApexMap/ApexMapView.h
  2. 332 0
      common/ApexMap/ApexMapView.m

+ 15 - 0
common/ApexMap/ApexMapView.h

@@ -0,0 +1,15 @@
+//
+//  ApexMapView.h
+//  OpenStreetMap
+//
+//  Created by Jack on 2019/1/18.
+//  Copyright © 2019 Jack Template. All rights reserved.
+//
+
+#import <MapKit/MapKit.h>
+
+
+@interface ApexMapView : MKMapView
+
+@end
+

+ 332 - 0
common/ApexMap/ApexMapView.m

@@ -0,0 +1,332 @@
+//
+//  ApexMapView.m
+//  OpenStreetMap
+//
+//  Created by Jack on 2019/1/18.
+//  Copyright © 2019 Jack Template. All rights reserved.
+//
+
+#import "ApexMapView.h"
+#import "UIView+RAConstraint.h"
+
+static NSString * const kTileSource = @"https://map.apexshipping.com/osm_tiles/{z}/{x}/{y}.png";
+static NSString * const kOpenStreetMapURL = @"https://www.openstreetmap.org/copyright";
+static NSString * const kCopyright = @"OpenStreetMap";
+
+@interface ApexMapView () <MKMapViewDelegate>
+
+@property (nonatomic,strong) UIButton *legalBtn;
+@property (nonatomic,strong) MKTileOverlay *tileOverlay;
+@property (nonatomic,weak) id<MKMapViewDelegate> internalDelegate;
+
+@end
+
+@implementation ApexMapView
+
+#pragma mark - Initial
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    if (self = [super initWithFrame:frame]) {
+        [self setupMapView];
+    }
+    return self;
+}
+
+- (void)awakeFromNib {
+    [super awakeFromNib];
+    [self setupMapView];
+}
+
+- (void)setupMapView {
+    
+    self.rotateEnabled = NO;
+    [self apex_setDelegate:self];
+    
+    [self addOverlay:self.tileOverlay];
+}
+
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    
+    NSArray<UIView *> *subViews = self.subviews;
+    for (UIView *subView in subViews) {
+        
+        if ([subView isMemberOfClass:NSClassFromString(@"MKAttributionLabel")]) {
+            [subView removeFromSuperview];
+        } else if ([subView isMemberOfClass:[UIImageView class]]) {
+            [subView removeFromSuperview];
+        }
+    }
+    if (![subViews containsObject:self.legalBtn]) {
+        [self setupLegalView];
+    }
+}
+
+- (void)setupLegalView {
+    
+    [self addSubview:self.legalBtn];
+    
+    [self.legalBtn ra_applyConstraints:^(RAConstraintMaker *maker) {
+       
+        maker.left.ra_equalTo(self.left).ra_offset(5.0f);
+        maker.bottom.ra_equalTo(self.bottom).ra_offset(-5.0f);
+    }];
+    
+}
+
+#pragma mark - Override
+
+- (void)setDelegate:(id<MKMapViewDelegate>)delegate {
+    if (delegate) {
+        __weak typeof(delegate) weakDelegate = delegate;
+        _internalDelegate = weakDelegate;
+    } else {
+        _internalDelegate = nil;
+    }
+}
+
+- (void)apex_setDelegate:(id<MKMapViewDelegate>)delegate {
+    [super setDelegate:delegate];
+}
+
+#pragma mark - Getter
+
+- (MKTileOverlay *)tileOverlay {
+    if (!_tileOverlay) {
+        _tileOverlay = [[MKTileOverlay alloc] initWithURLTemplate:kTileSource];
+        _tileOverlay.canReplaceMapContent = YES;
+        _tileOverlay.minimumZ = 1;
+        _tileOverlay.maximumZ = 18;
+    }
+    return _tileOverlay;
+}
+
+- (UIButton *)legalBtn {
+    if (!_legalBtn) {
+        _legalBtn = [UIButton buttonWithType:UIButtonTypeSystem];
+        _legalBtn.titleLabel.font = [UIFont systemFontOfSize:12.0f];
+        [_legalBtn setTitle:kCopyright forState:UIControlStateNormal];
+        [_legalBtn addTarget:self action:@selector(legalButtonDidClick:) forControlEvents:UIControlEventTouchUpInside];
+    }
+    return _legalBtn;
+}
+
+#pragma mark - User Action
+
+- (void)legalButtonDidClick:(id)sender {
+    
+    NSURL *url = [NSURL URLWithString:kOpenStreetMapURL];
+    if ([[UIApplication sharedApplication] canOpenURL:url]) {
+        if (@available(iOS 10, *)) {
+            [[UIApplication sharedApplication] openURL:url options:@{UIApplicationOpenURLOptionsSourceApplicationKey: @YES} completionHandler:^(BOOL success) {
+                
+            }];
+        } else{
+            [[UIApplication sharedApplication] openURL:url];
+        }
+    }
+}
+
+#pragma mark - MKMapViewDelegate
+
+- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated {
+    
+    if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:regionWillChangeAnimated:)]) {
+        [_internalDelegate mapView:mapView regionWillChangeAnimated:animated];
+    }
+}
+- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
+    
+    if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:regionDidChangeAnimated:)]) {
+        [_internalDelegate mapView:mapView regionDidChangeAnimated:animated];
+    }
+}
+
+- (void)mapViewDidChangeVisibleRegion:(MKMapView *)mapView {
+    
+    if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapViewDidChangeVisibleRegion:)]) {
+        [_internalDelegate mapViewDidChangeVisibleRegion:mapView];
+    }
+}
+
+- (void)mapViewWillStartLoadingMap:(MKMapView *)mapView {
+    
+    if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapViewWillStartLoadingMap:)]) {
+        [_internalDelegate mapViewWillStartLoadingMap:mapView];
+    }
+}
+
+- (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView {
+    
+    if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapViewDidFinishLoadingMap:)]) {
+        [_internalDelegate mapViewDidFinishLoadingMap:mapView];
+    }
+}
+
+- (void)mapViewDidFailLoadingMap:(MKMapView *)mapView withError:(NSError *)error {
+    
+    if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapViewDidFailLoadingMap:withError:)]) {
+        [_internalDelegate mapViewDidFailLoadingMap:mapView withError:error];
+    }
+}
+
+- (void)mapViewWillStartRenderingMap:(MKMapView *)mapView {
+    
+    if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapViewWillStartRenderingMap:)]) {
+        [_internalDelegate mapViewWillStartRenderingMap:mapView];
+    }
+}
+
+- (void)mapViewDidFinishRenderingMap:(MKMapView *)mapView fullyRendered:(BOOL)fullyRendered {
+    
+    if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapViewDidFinishRenderingMap:fullyRendered:)]) {
+        [_internalDelegate mapViewDidFinishRenderingMap:mapView fullyRendered:fullyRendered];
+    }
+}
+
+// mapView:viewForAnnotation: provides the view for each annotation.
+// This method may be called for all or some of the added annotations.
+// For MapKit provided annotations (eg. MKUserLocation) return nil to use the MapKit provided annotation view.
+- (nullable MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
+    
+    if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:viewForAnnotation:)]) {
+        return [_internalDelegate mapView:mapView viewForAnnotation:annotation];
+    }
+    return nil;
+}
+
+// mapView:didAddAnnotationViews: is called after the annotation views have been added and positioned in the map.
+// The delegate can implement this method to animate the adding of the annotations views.
+// Use the current positions of the annotation views as the destinations of the animation.
+- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray<MKAnnotationView *> *)views {
+    
+    if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:didAddAnnotationViews:)]) {
+        [_internalDelegate mapView:mapView didAddAnnotationViews:views];
+    }
+}
+
+#if TARGET_OS_IPHONE
+// mapView:annotationView:calloutAccessoryControlTapped: is called when the user taps on left & right callout accessory UIControls.
+- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
+    
+    if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:annotationView:calloutAccessoryControlTapped:)]) {
+        [_internalDelegate mapView:mapView annotationView:view calloutAccessoryControlTapped:control];
+    }
+}
+#endif
+
+- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view {
+    
+    if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:didSelectAnnotationView:)]) {
+        [_internalDelegate mapView:mapView didSelectAnnotationView:view];
+    }
+}
+
+- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view {
+    
+    if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:didDeselectAnnotationView:)]) {
+        [_internalDelegate mapView:mapView didDeselectAnnotationView:view];
+    }
+}
+
+- (void)mapViewWillStartLocatingUser:(MKMapView *)mapView {
+    
+    if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapViewWillStartLocatingUser:)]) {
+        [_internalDelegate mapViewWillStartLocatingUser:mapView];
+    }
+}
+
+- (void)mapViewDidStopLocatingUser:(MKMapView *)mapView {
+    
+    if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapViewDidStopLocatingUser:)]) {
+        [_internalDelegate mapViewDidStopLocatingUser:mapView];
+    }
+}
+
+- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation {
+    
+    if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:didUpdateUserLocation:)]) {
+        [_internalDelegate mapView:mapView didUpdateUserLocation:userLocation];
+    }
+}
+
+- (void)mapView:(MKMapView *)mapView didFailToLocateUserWithError:(NSError *)error {
+    
+    if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:didFailToLocateUserWithError:)]) {
+        [_internalDelegate mapView:mapView didFailToLocateUserWithError:error];
+    }
+}
+
+- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view didChangeDragState:(MKAnnotationViewDragState)newState
+   fromOldState:(MKAnnotationViewDragState)oldState {
+    
+    if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:annotationView:didChangeDragState:fromOldState:)]) {
+        [_internalDelegate mapView:mapView annotationView:view didChangeDragState:newState fromOldState:oldState];
+    }
+}
+
+#if TARGET_OS_IPHONE
+- (void)mapView:(MKMapView *)mapView didChangeUserTrackingMode:(MKUserTrackingMode)mode animated:(BOOL)animated {
+    
+    if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:didChangeUserTrackingMode:animated:)]) {
+        [_internalDelegate mapView:mapView didChangeUserTrackingMode:mode animated:animated];
+    }
+}
+#endif
+
+- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id <MKOverlay>)overlay {
+    
+    if (overlay == self.tileOverlay) {
+        
+        return [[MKTileOverlayRenderer alloc] initWithTileOverlay:overlay];
+    } else {
+        if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:rendererForOverlay:)]) {
+            return [_internalDelegate mapView:mapView rendererForOverlay:overlay];
+        } else {
+            return nil;
+        }
+    }
+}
+
+- (void)mapView:(MKMapView *)mapView didAddOverlayRenderers:(NSArray<MKOverlayRenderer *> *)renderers {
+    
+    if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:didAddOverlayRenderers:)]) {
+        [_internalDelegate mapView:mapView didAddOverlayRenderers:renderers];
+    }
+}
+
+#if TARGET_OS_IPHONE
+// Prefer -mapView:rendererForOverlay:
+- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay {
+    
+    if (overlay == self.tileOverlay) {
+        
+        return [[MKOverlayView alloc] initWithOverlay:overlay];
+    } else {
+        if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:viewForOverlay:)]) {
+            return [_internalDelegate mapView:mapView viewForOverlay:overlay];
+        } else {
+            return nil;
+        }
+    }
+}
+
+// Called after the provided overlay views have been added and positioned in the map.
+// Prefer -mapView:didAddOverlayRenderers:
+- (void)mapView:(MKMapView *)mapView didAddOverlayViews:(NSArray *)overlayViews {
+    
+    if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:didAddOverlayViews:)]) {
+        [_internalDelegate mapView:mapView didAddOverlayViews:overlayViews];
+    }
+}
+#endif
+
+// Return nil for default MKClusterAnnotation, it is illegal to return a cluster annotation not containing the identical array of member annotations given.
+- (MKClusterAnnotation *)mapView:(MKMapView *)mapView clusterAnnotationForMemberAnnotations:(NSArray<id<MKAnnotation>>*)memberAnnotations {
+    
+    if (_internalDelegate && [_internalDelegate respondsToSelector:@selector(mapView:clusterAnnotationForMemberAnnotations:)]) {
+        return [_internalDelegate mapView:mapView clusterAnnotationForMemberAnnotations:memberAnnotations];
+    }
+    return nil;
+}
+@end