Mapbox使用詳解


一、簡介:

Mapbox致力於打造全球最漂亮的個性化地圖。
 
在一次偶然的地圖相關資料搜索過程中發現了一個很神奇又很漂亮的地圖,這個地圖支持高度自定義各種地圖元素,比如,道路,水系,綠地,建築物,背景色,等等。Mapbox打造的Mapbox studio地圖制作虛擬工作室,就是一個很完美的地圖元素個性化編輯器。另外,我們也可以把自己項目的地理信息數據上傳到Mapbox雲端,然后在自己項目的客戶端展現出來。
 
Mapbox地圖數據來源於Open Street Map(OSM)等其他地圖數據供應商,和Google Map、Apple Map等地圖廠商的地圖數據來源差不多。
 
 

二、使用:

1、注冊賬號:

在  https://www.mapbox.com 網址找到 sign up 注冊一個開發者賬號。
進入個人中心后,我們能看到 Integrate Mapbox 字樣,我們點進去,然后根據網頁的引導,我們最終會得到一個
和我們的項目相關的 Access tokens ,這個 tokens 就是我們訪問SDK的唯一key,
 
選擇SDK平台,這里我們選擇iOS
然后選擇 Cocoapod 安裝方式:
再接下來我們就能看到 Access tokens 了:

2、引入工程:

這里我們使用下載好的 Mapbox.framework 做示例,當然使用 cocoa pod 也行。
  • 把Mapbox.frameworks 文件拖拽到 “ 項目 -> TARGETS -> Build Phases -> Embed Frameworks ” 這個路徑下;
  • 在路徑 “項目 -> TARGETS -> Build Phases ->  +  -> New Run Script phase” 粘貼一串 shel l腳本代碼 : 
    bash "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/Mapbox.framework/strip-frameworks.sh"
 
 
接下來把我們的 Access tokens 填寫到項目工程的 Info.plist 文件中:
  •  在Info.plist 文件中添加 key 為 MGLMapboxAccessToken 其值為【Access tokens】 字符串;
  •  在Info.plist 文件中添加 key 為 NSLocationWhenInUseUsageDescription 其值為 bool 類型的 YES;
   
 

3、Mapbox.framework類的使用:

【1】加載地圖:

  1.  
    #import "LoadMapboxViewController.h"
  2.  
    #import <Mapbox/Mapbox.h>
  3.  
     
  4.  
    @interface LoadMapboxViewController ()<MGLMapViewDelegate>
  5.  
     
  6.  
    @property (nonatomic, strong) MGLMapView *mapView;
  7.  
     
  8.  
    @end
  9.  
     
  10.  
    @implementation LoadMapboxViewController
  11.  
     
  12.  
    - ( void)viewDidLoad {
  13.  
    [ super viewDidLoad];
  14.  
    // Do any additional setup after loading the view.
  15.  
     
  16.  
    self.title = @"加載地圖";
  17.  
     
  18.  
    [ self.view addSubview:self.mapView];
  19.  
    }
  20.  
     
  21.  
    - (MGLMapView *)mapView {
  22.  
    if (_mapView == nil) {
  23.  
    //設置地圖的 frame 和 地圖個性化樣式
  24.  
    _mapView = [[MGLMapView alloc] initWithFrame: self.view.bounds styleURL:[NSURL URLWithString:@"mapbox://styles/mapbox/streets-v10"]];
  25.  
    _mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
  26.  
    //設置地圖默認顯示的地點和縮放等級
  27.  
    [_mapView setCenterCoordinate: CLLocationCoordinate2DMake(39.980528, 116.306745) zoomLevel:15 animated:YES];
  28.  
    //顯示用戶位置
  29.  
    _mapView.showsUserLocation = YES;
  30.  
    //定位模式
  31.  
    _mapView.userTrackingMode = MGLUserTrackingModeFollow;
  32.  
    //是否傾斜地圖
  33.  
    _mapView.pitchEnabled = YES;
  34.  
    //是否旋轉地圖
  35.  
    _mapView.rotateEnabled = NO;
  36.  
    //代理
  37.  
    _mapView.delegate = self;
  38.  
    }
  39.  
    return _mapView;
  40.  
    }
  41.  
     
  42.  
    @end

【2】加載各種樣式的地圖:

我們可以通過如下代碼修改地圖樣式:
[self.mapView setStyleURL:[NSURL URLWithString:@"mapbox://styles/mapbox/streets-v10"]]; 
這是所有地圖已經做好的模板樣式參數:

 

  • mapbox://styles/mapbox/streets-v10
  • mapbox://styles/mapbox/outdoors-v10
  • mapbox://styles/mapbox/light-v9
  • mapbox://styles/mapbox/dark-v9
  • mapbox://styles/mapbox/satellite-v9
  • mapbox://styles/mapbox/satellite-streets-v10
  • mapbox://styles/mapbox/navigation-preview-day-v2
  • mapbox://styles/mapbox/navigation-preview-night-v2
  • mapbox://styles/mapbox/navigation-guidance-day-v2
  • mapbox://styles/mapbox/navigation-guidance-night-v2

 

 
使用不同的參數呈現出來的地圖風格變不一樣。

【3】加載大頭針和默認氣泡:

  1.  
    //
  2.  
    // DefaultAnnotationCalloutViewController.m
  3.  
    // MapboxExample
  4.  
    //
  5.  
    // Created by iron on 2018/1/30.
  6.  
    // Copyright © 2018年 wangzhengang. All rights reserved.
  7.  
    //
  8.  
     
  9.  
    #import "DefaultAnnotationCalloutViewController.h"
  10.  
    #import <Mapbox/Mapbox.h>
  11.  
     
  12.  
    @interface DefaultAnnotationCalloutViewController ()<MGLMapViewDelegate>
  13.  
    @property (nonatomic, strong) MGLMapView *mapView;
  14.  
    @property (nonatomic, copy) NSArray *annotationsArray;
  15.  
    @end
  16.  
     
  17.  
    @implementation DefaultAnnotationCalloutViewController
  18.  
     
  19.  
    - ( void)dealloc {
  20.  
    [_mapView removeFromSuperview];
  21.  
    _mapView.delegate = nil;
  22.  
    _mapView = nil;
  23.  
    }
  24.  
     
  25.  
    - ( void)viewDidLoad {
  26.  
    [ super viewDidLoad];
  27.  
     
  28.  
    [ self.view addSubview:self.mapView];
  29.  
    }
  30.  
     
  31.  
    - ( void)didReceiveMemoryWarning {
  32.  
    [ super didReceiveMemoryWarning];
  33.  
    // Dispose of any resources that can be recreated.
  34.  
    }
  35.  
     
  36.  
     
  37.  
    - (MGLMapView *)mapView {
  38.  
    if (_mapView == nil) {
  39.  
    //設置地圖的 frame 和 地圖個性化樣式
  40.  
    _mapView = [[MGLMapView alloc] initWithFrame: self.view.bounds styleURL:[NSURL URLWithString:@"mapbox://styles/mapbox/streets-v10"]];
  41.  
    _mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
  42.  
    //設置地圖默認顯示的地點和縮放等級
  43.  
    [_mapView setCenterCoordinate: CLLocationCoordinate2DMake(39.980528, 116.306745) zoomLevel:15 animated:NO];
  44.  
    //顯示用戶位置
  45.  
    _mapView.showsUserLocation = YES;
  46.  
    //定位模式
  47.  
    _mapView.userTrackingMode = MGLUserTrackingModeNone;
  48.  
    //是否傾斜地圖
  49.  
    _mapView.pitchEnabled = YES;
  50.  
    //是否旋轉地圖
  51.  
    _mapView.rotateEnabled = NO;
  52.  
    //代理
  53.  
    _mapView.delegate = self;
  54.  
    }
  55.  
    return _mapView;
  56.  
    }
  57.  
     
  58.  
    - ( NSArray *)annotationsArray {
  59.  
    if (_annotationsArray == nil) {
  60.  
    CLLocationCoordinate2D coords[2];
  61.  
    coords[ 0] = CLLocationCoordinate2DMake(39.980528, 116.306745);
  62.  
    coords[ 1] = CLLocationCoordinate2DMake(40.000, 116.306745);
  63.  
    NSMutableArray *pointsArray = [NSMutableArray array];
  64.  
    for (NSInteger i = 0; i < 2; ++i) {
  65.  
    MGLPointAnnotation *pointAnnotation = [[MGLPointAnnotation alloc] init];
  66.  
    pointAnnotation.coordinate = coords[i];
  67.  
    pointAnnotation.title = [ NSString stringWithFormat:@"title:%ld", (long)i];
  68.  
    pointAnnotation.subtitle = [ NSString stringWithFormat:@"subtitle: %ld%ld%ld", (long)i,(long)i,(long)i];
  69.  
    [pointsArray addObject:pointAnnotation];
  70.  
    }
  71.  
    _annotationsArray = [pointsArray copy];
  72.  
    }
  73.  
    return _annotationsArray;
  74.  
    }
  75.  
     
  76.  
    #pragma mark MGLMapViewDelegate
  77.  
     
  78.  
    - ( void)mapViewDidFinishLoadingMap:(MGLMapView *)mapView {
  79.  
    ///地圖加載完成時加載大頭針
  80.  
    [mapView addAnnotations: self.annotationsArray];
  81.  
    }
  82.  
     
  83.  
    - (MGLAnnotationView *)mapView:(MGLMapView *)mapView viewForAnnotation:( id<MGLAnnotation>)annotation {
  84.  
    if (![annotation isKindOfClass:[MGLPointAnnotation class]]) {
  85.  
    return nil;
  86.  
    }
  87.  
    MGLAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier: @"MGLAnnotationView"];
  88.  
    if (annotationView == nil) {
  89.  
    annotationView = [[MGLAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier: @"MGLAnnotationView"];
  90.  
    [annotationView setFrame: CGRectMake(0, 0, 40, 40)];
  91.  
    [annotationView setBackgroundColor:[ UIColor redColor]];
  92.  
    annotationView.layer.cornerRadius = 20.f;
  93.  
    annotationView.layer.masksToBounds= YES;
  94.  
    annotationView.layer.borderColor = [ UIColor whiteColor].CGColor;
  95.  
    annotationView.layer.borderWidth = 5.f;
  96.  
    }
  97.  
    return annotationView;
  98.  
    }
  99.  
     
  100.  
    ///是否顯示氣泡
  101.  
    -( BOOL)mapView:(MGLMapView *)mapView annotationCanShowCallout:(id<MGLAnnotation>)annotation {
  102.  
    return YES;
  103.  
    }
  104.  
    ///完成加載大頭針
  105.  
    - ( void)mapView:(MGLMapView *)mapView didAddAnnotationViews:(NSArray<MGLAnnotationView *> *)annotationViews {
  106.  
    [mapView showAnnotations: self.annotationsArray edgePadding:UIEdgeInsetsMake(100, 50, 100, 50) animated:YES];
  107.  
    }
  108.  
     
  109.  
    ///氣泡左側視圖
  110.  
    - ( UIView *)mapView:(MGLMapView *)mapView leftCalloutAccessoryViewForAnnotation:(id<MGLAnnotation>)annotation {
  111.  
    UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
  112.  
    view.backgroundColor= [ UIColor blueColor];
  113.  
    UILabel *lab = [[UILabel alloc] initWithFrame:view.bounds];
  114.  
    lab.text = @"左側視圖";
  115.  
    lab.textColor = [ UIColor whiteColor];
  116.  
    lab.font = [ UIFont systemFontOfSize:10];
  117.  
    lab.textAlignment = NSTextAlignmentCenter;
  118.  
    [view addSubview:lab];
  119.  
    return view;
  120.  
    }
  121.  
    ///氣泡右側視圖,
  122.  
    - ( UIView *)mapView:(MGLMapView *)mapView rightCalloutAccessoryViewForAnnotation:(id<MGLAnnotation>)annotation {
  123.  
    UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
  124.  
    view.backgroundColor= [ UIColor greenColor];
  125.  
    UILabel *lab = [[UILabel alloc] initWithFrame:view.bounds];
  126.  
    lab.text = @"右側視圖";
  127.  
    lab.textColor = [ UIColor blackColor];
  128.  
    lab.font = [ UIFont systemFontOfSize:10];
  129.  
    [view addSubview:lab];
  130.  
    return view;
  131.  
    }
  132.  
     
  133.  
     
  134.  
     
  135.  
     
  136.  
    @end

【4】加載圖片大頭針和自定義氣泡:

  • 創建一個繼承 UIview 的類 CustomeMapViewCalloutView  並遵守 < MGLCalloutView > 這個協議;      
  • 在 CustomeMapViewCalloutView 中實現各種需求;

          
實現自定義callout view:
  1.  
    //
  2.  
    // CustomeMapViewCalloutView.h
  3.  
    // Etoury
  4.  
    //
  5.  
    // Created by iron on 2017/5/21.
  6.  
    // Copyright © 2017年 iron. All rights reserved.
  7.  
    //
  8.  
     
  9.  
    #import <UIKit/UIKit.h>
  10.  
    #import <Mapbox/Mapbox.h>
  11.  
     
  12.  
    @interface CustomeMapViewCalloutView : UIView<MGLCalloutView>
  13.  
     
  14.  
     
  15.  
     
  16.  
    @end
  1.  
    //
  2.  
    // CustomeMapViewCalloutView.m
  3.  
    // Etoury
  4.  
    //
  5.  
    // Created by iron on 2017/5/21.
  6.  
    // Copyright © 2017年 iron. All rights reserved.
  7.  
    //
  8.  
     
  9.  
    #import "CustomeMapViewCalloutView.h"
  10.  
     
  11.  
    // Set defaults for custom tip drawing
  12.  
    static CGFloat const tipHeight = 10.0;
  13.  
    static CGFloat const tipWidth = 20.0;
  14.  
     
  15.  
    @interface CustomeMapViewCalloutView ()
  16.  
    @property (strong, nonatomic) UIButton *mainBody;
  17.  
    @end
  18.  
     
  19.  
    @implementation CustomeMapViewCalloutView {
  20.  
    id <MGLAnnotation> _representedObject;
  21.  
    __unused UIView *_leftAccessoryView;/* unused */
  22.  
    __unused UIView *_rightAccessoryView;/* unused */
  23.  
    __ weak id <MGLCalloutViewDelegate> _delegate;
  24.  
    BOOL _dismissesAutomatically;
  25.  
    BOOL _anchoredToAnnotation;
  26.  
    }
  27.  
     
  28.  
    @synthesize representedObject = _representedObject;
  29.  
    @synthesize leftAccessoryView = _leftAccessoryView;/* unused */
  30.  
    @synthesize rightAccessoryView = _rightAccessoryView;/* unused */
  31.  
    @synthesize delegate = _delegate;
  32.  
    @synthesize anchoredToAnnotation = _anchoredToAnnotation;
  33.  
    @synthesize dismissesAutomatically = _dismissesAutomatically;
  34.  
     
  35.  
    - ( instancetype)initWithFrame:(CGRect)frame
  36.  
    {
  37.  
    self = [super initWithFrame:frame];
  38.  
    if (self)
  39.  
    {
  40.  
    self.backgroundColor = [UIColor clearColor];
  41.  
     
  42.  
    // Create and add a subview to hold the callout’s text
  43.  
    UIButton *mainBody = [UIButton buttonWithType:UIButtonTypeSystem];
  44.  
    mainBody.backgroundColor = [ self backgroundColorForCallout];
  45.  
    mainBody.tintColor = [ UIColor whiteColor];
  46.  
    mainBody.contentEdgeInsets = UIEdgeInsetsMake(10.0, 10.0, 10.0, 10.0);
  47.  
    mainBody.layer.cornerRadius = 4.0;
  48.  
    self.mainBody = mainBody;
  49.  
     
  50.  
    [ self addSubview:self.mainBody];
  51.  
    }
  52.  
     
  53.  
    return self;
  54.  
    }
  55.  
     
  56.  
     
  57.  
    #pragma mark - MGLCalloutView API
  58.  
     
  59.  
    - ( void)presentCalloutFromRect:(CGRect)rect inView:(UIView *)view constrainedToView:(UIView *)constrainedView animated:(BOOL)animated
  60.  
    {
  61.  
    // Do not show a callout if there is no title set for the annotation
  62.  
    if (![self.representedObject respondsToSelector:@selector(title)])
  63.  
    {
  64.  
    return;
  65.  
    }
  66.  
     
  67.  
    [view addSubview: self];
  68.  
     
  69.  
    // Prepare title label
  70.  
    [ self.mainBody setTitle:self.representedObject.title forState:UIControlStateNormal];
  71.  
    [ self.mainBody sizeToFit];
  72.  
     
  73.  
    if ([self isCalloutTappable])
  74.  
    {
  75.  
    // Handle taps and eventually try to send them to the delegate (usually the map view)
  76.  
    [ self.mainBody addTarget:self action:@selector(calloutTapped) forControlEvents:UIControlEventTouchUpInside];
  77.  
    }
  78.  
    else
  79.  
    {
  80.  
    // Disable tapping and highlighting
  81.  
    self.mainBody.userInteractionEnabled = NO;
  82.  
    }
  83.  
     
  84.  
    // Prepare our frame, adding extra space at the bottom for the tip
  85.  
    CGFloat frameWidth = self.mainBody.bounds.size.width;
  86.  
    CGFloat frameHeight = self.mainBody.bounds.size.height + tipHeight;
  87.  
    CGFloat frameOriginX = rect.origin.x + (rect.size.width/2.0) - (frameWidth/2.0);
  88.  
    CGFloat frameOriginY = rect.origin.y - frameHeight;
  89.  
    self.frame = CGRectMake(frameOriginX, frameOriginY,
  90.  
    frameWidth, frameHeight);
  91.  
     
  92.  
    if (animated)
  93.  
    {
  94.  
    self.alpha = 0.0;
  95.  
     
  96.  
    [ UIView animateWithDuration:0.2 animations:^{
  97.  
    self.alpha = 1.0;
  98.  
    }];
  99.  
    }
  100.  
    }
  101.  
     
  102.  
    - ( void)dismissCalloutAnimated:(BOOL)animated
  103.  
    {
  104.  
    if (self.superview)
  105.  
    {
  106.  
    if (animated)
  107.  
    {
  108.  
    [ UIView animateWithDuration:0.2 animations:^{
  109.  
    self.alpha = 0.0;
  110.  
    } completion:^( BOOL finished) {
  111.  
    [ self removeFromSuperview];
  112.  
    }];
  113.  
    }
  114.  
    else
  115.  
    {
  116.  
    [ self removeFromSuperview];
  117.  
    }
  118.  
    }
  119.  
    }
  120.  
     
  121.  
    // Allow the callout to remain open during panning.
  122.  
    - ( BOOL)dismissesAutomatically {
  123.  
    return NO;
  124.  
    }
  125.  
     
  126.  
    - ( BOOL)isAnchoredToAnnotation {
  127.  
    return YES;
  128.  
    }
  129.  
     
  130.  
    // https://github.com/mapbox/mapbox-gl-native/issues/9228
  131.  
    - ( void)setCenter:(CGPoint)center {
  132.  
    center.y = center.y - CGRectGetMidY(self.bounds);
  133.  
    [ super setCenter:center];
  134.  
    }
  135.  
     
  136.  
    #pragma mark - Callout interaction handlers
  137.  
     
  138.  
    - ( BOOL)isCalloutTappable
  139.  
    {
  140.  
    if ([self.delegate respondsToSelector:@selector(calloutViewShouldHighlight:)]) {
  141.  
    return [self.delegate performSelector:@selector(calloutViewShouldHighlight:) withObject:self];
  142.  
    }
  143.  
     
  144.  
    return NO;
  145.  
    }
  146.  
     
  147.  
    - ( void)calloutTapped
  148.  
    {
  149.  
    if ([self isCalloutTappable] && [self.delegate respondsToSelector:@selector(calloutViewTapped:)])
  150.  
    {
  151.  
    [ self.delegate performSelector:@selector(calloutViewTapped:) withObject:self];
  152.  
    }
  153.  
    }
  154.  
     
  155.  
    #pragma mark - Custom view styling
  156.  
     
  157.  
    - ( UIColor *)backgroundColorForCallout
  158.  
    {
  159.  
    return [UIColor darkGrayColor];
  160.  
    }
  161.  
     
  162.  
    - ( void)drawRect:(CGRect)rect
  163.  
    {
  164.  
    // Draw the pointed tip at the bottom
  165.  
    UIColor *fillColor = [self backgroundColorForCallout];
  166.  
     
  167.  
    CGFloat tipLeft = rect.origin.x + (rect.size.width / 2.0) - (tipWidth / 2.0);
  168.  
    CGPoint tipBottom = CGPointMake(rect.origin.x + (rect.size.width / 2.0), rect.origin.y + rect.size.height);
  169.  
    CGFloat heightWithoutTip = rect.size.height - tipHeight - 1;
  170.  
     
  171.  
    CGContextRef currentContext = UIGraphicsGetCurrentContext();
  172.  
     
  173.  
    CGMutablePathRef tipPath = CGPathCreateMutable();
  174.  
    CGPathMoveToPoint(tipPath, NULL, tipLeft, heightWithoutTip);
  175.  
    CGPathAddLineToPoint(tipPath, NULL, tipBottom.x, tipBottom.y);
  176.  
    CGPathAddLineToPoint(tipPath, NULL, tipLeft + tipWidth, heightWithoutTip);
  177.  
    CGPathCloseSubpath(tipPath);
  178.  
     
  179.  
    [fillColor setFill];
  180.  
    CGContextAddPath(currentContext, tipPath);
  181.  
    CGContextFillPath(currentContext);
  182.  
    CGPathRelease(tipPath);
  183.  
    }
  184.  
     
  185.  
     
  186.  
     
  187.  
     
  188.  
     
  189.  
    @end

在view controller中使用自定義的callout view:
  1.  
    //
  2.  
    // CustomeAnnotationCalloutViewController.m
  3.  
    // MapboxExample
  4.  
    //
  5.  
    // Created by iron on 2018/1/30.
  6.  
    // Copyright © 2018年 wangzhengang. All rights reserved.
  7.  
    //
  8.  
     
  9.  
    #import "CustomeAnnotationCalloutViewController.h"
  10.  
    #import <Mapbox/Mapbox.h>
  11.  
    #import "CustomeMapViewCalloutView.h"
  12.  
     
  13.  
    @interface CustomeAnnotationCalloutViewController ()<MGLMapViewDelegate>
  14.  
    @property (nonatomic, strong) MGLMapView *mapView;
  15.  
    @property (nonatomic, copy) NSArray *annotationsArray;
  16.  
     
  17.  
    @end
  18.  
     
  19.  
    @implementation CustomeAnnotationCalloutViewController
  20.  
     
  21.  
     
  22.  
    - ( void)dealloc {
  23.  
    [_mapView removeFromSuperview];
  24.  
    _mapView.delegate = nil;
  25.  
    _mapView = nil;
  26.  
    }
  27.  
     
  28.  
     
  29.  
    - ( void)viewDidLoad {
  30.  
    [ super viewDidLoad];
  31.  
     
  32.  
    [ self.view addSubview:self.mapView];
  33.  
    }
  34.  
     
  35.  
     
  36.  
    - (MGLMapView *)mapView {
  37.  
    if (_mapView == nil) {
  38.  
    //設置地圖的 frame 和 地圖個性化樣式
  39.  
    _mapView = [[MGLMapView alloc] initWithFrame: self.view.bounds styleURL:[NSURL URLWithString:@"mapbox://styles/mapbox/streets-v10"]];
  40.  
    _mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
  41.  
    //設置地圖默認顯示的地點和縮放等級
  42.  
    [_mapView setCenterCoordinate: CLLocationCoordinate2DMake(39.980528, 116.306745) zoomLevel:15 animated:NO];
  43.  
    //顯示用戶位置
  44.  
    _mapView.showsUserLocation = YES;
  45.  
    //定位模式
  46.  
    _mapView.userTrackingMode = MGLUserTrackingModeNone;
  47.  
    //是否傾斜地圖
  48.  
    _mapView.pitchEnabled = YES;
  49.  
    //是否旋轉地圖
  50.  
    _mapView.rotateEnabled = NO;
  51.  
    //代理
  52.  
    _mapView.delegate = self;
  53.  
    }
  54.  
    return _mapView;
  55.  
    }
  56.  
     
  57.  
    - ( NSArray *)annotationsArray {
  58.  
    if (_annotationsArray == nil) {
  59.  
    CLLocationCoordinate2D coords[2];
  60.  
    coords[ 0] = CLLocationCoordinate2DMake(39.980528, 116.306745);
  61.  
    coords[ 1] = CLLocationCoordinate2DMake(40.000, 116.306745);
  62.  
    NSMutableArray *pointsArray = [NSMutableArray array];
  63.  
    for (NSInteger i = 0; i < 2; ++i) {
  64.  
    MGLPointAnnotation *pointAnnotation = [[MGLPointAnnotation alloc] init];
  65.  
    pointAnnotation.coordinate = coords[i];
  66.  
    pointAnnotation.title = [ NSString stringWithFormat:@"title:%ld", (long)i];
  67.  
    pointAnnotation.subtitle = [ NSString stringWithFormat:@"subtitle: %ld%ld%ld", (long)i,(long)i,(long)i];
  68.  
    [pointsArray addObject:pointAnnotation];
  69.  
    }
  70.  
    _annotationsArray = [pointsArray copy];
  71.  
    }
  72.  
    return _annotationsArray;
  73.  
    }
  74.  
     
  75.  
     
  76.  
    #pragma mark MGLMapViewDelegate
  77.  
    - ( void)mapViewDidFinishLoadingMap:(MGLMapView *)mapView {
  78.  
    ///地圖加載完成時加載大頭針
  79.  
    [mapView addAnnotations: self.annotationsArray];
  80.  
    }
  81.  
     
  82.  
    - (MGLAnnotationView *)mapView:(MGLMapView *)mapView viewForAnnotation:( id<MGLAnnotation>)annotation {
  83.  
    if (![annotation isKindOfClass:[MGLPointAnnotation class]]) {
  84.  
    return nil;
  85.  
    }
  86.  
    MGLAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier: @"MGLAnnotationView"];
  87.  
    if (annotationView == nil) {
  88.  
    annotationView = [[MGLAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier: @"MGLAnnotationView"];
  89.  
    [annotationView setFrame: CGRectMake(0, 0, 40, 40)];
  90.  
    [annotationView setBackgroundColor:[ UIColor redColor]];
  91.  
    annotationView.layer.cornerRadius = 20.f;
  92.  
    annotationView.layer.masksToBounds= YES;
  93.  
    annotationView.layer.borderColor = [ UIColor whiteColor].CGColor;
  94.  
    annotationView.layer.borderWidth = 5.f;
  95.  
    }
  96.  
    return annotationView;
  97.  
    }
  98.  
     
  99.  
    ///是否顯示氣泡
  100.  
    -( BOOL)mapView:(MGLMapView *)mapView annotationCanShowCallout:(id<MGLAnnotation>)annotation {
  101.  
    return YES;
  102.  
    }
  103.  
    ///完成加載大頭針
  104.  
    - ( void)mapView:(MGLMapView *)mapView didAddAnnotationViews:(NSArray<MGLAnnotationView *> *)annotationViews {
  105.  
    [mapView showAnnotations: self.annotationsArray edgePadding:UIEdgeInsetsMake(100, 50, 100, 50) animated:YES];
  106.  
    }
  107.  
     
  108.  
    ///加載定義callout view
  109.  
    - ( id<MGLCalloutView>)mapView:(MGLMapView *)mapView calloutViewForAnnotation:(id<MGLAnnotation>)annotation {
  110.  
    CustomeMapViewCalloutView *calloutView = [[CustomeMapViewCalloutView alloc] init];
  111.  
    calloutView.representedObject = annotation;
  112.  
    return calloutView;
  113.  
    }
  114.  
     
  115.  
    ///氣泡點擊事件
  116.  
    - ( void)mapView:(MGLMapView *)mapView tapOnCalloutForAnnotation:(id<MGLAnnotation>)annotation {
  117.  
    NSLog(@"點擊了氣泡: %@", annotation);
  118.  
    [mapView deselectAnnotation:annotation animated: YES];
  119.  
     
  120.  
    [ self showAlertControllerWithViewContorller:self title:@"點擊了氣泡" message:nil leftButtonTitle:nil rightButtonTitle:@"確定"];
  121.  
    }
  122.  
     
  123.  
     
  124.  
    #pragma mark - 警告框
  125.  
    - ( void)showAlertControllerWithViewContorller:(UIViewController *)viewController title:(NSString *)title message:(NSString *)message leftButtonTitle:(NSString *)leftBtnTitle rightButtonTitle:(NSString *)rightBtnTitle {
  126.  
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
  127.  
    if (leftBtnTitle) {
  128.  
    [alert addAction:[ UIAlertAction actionWithTitle:leftBtnTitle style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
  129.  
     
  130.  
    }]];
  131.  
    }
  132.  
    if (rightBtnTitle) {
  133.  
    [alert addAction:[ UIAlertAction actionWithTitle:rightBtnTitle style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
  134.  
     
  135.  
    }]];
  136.  
    }
  137.  
    [viewController presentViewController:alert animated: YES completion:nil];
  138.  
    }
  139.  
     
  140.  
     
  141.  
    @end
效果如下:

【5】繪制線段和多邊形:

老實說 Mapbox 的 繪制線段和多邊形的相關類,相比高德地圖和百度地圖寫的並不好,用起來很不方便,比如:

 

  •  MGLPolygon 有 strokeColor 這個參數,卻沒有設置 描邊線寬度和樣式的參數;
  •  MGLPolyline 沒有 strokeColor 和 fillColor 之分,而且畫虛線的代碼寫起來很麻煩;
總體來講,MGLPolygon 和 MGLPolyline 這兩個類沒有高德地圖和百度地圖那樣使用起來方便,另外,MGLPolyline 這個類中的 MGLShapeSource 、MGLStyleLayer 雖然使用起來很麻煩,但是相對來說倒是保持了靈活性。

 

 

為了提高 MGLPolygon 和 MGLPolyline 的使用便利性,我對 MGLPolygon 、MGLPolyline 的基類 MGLShape 擴展了幾個屬性:

 

  • @property (nonatomic, strong) UIColor *fillColor;//填充顏色
  • @property (nonatomic, assign) CGFloat fillOpacity;//填充透明度
  • @property (nonatomic, strong) UIColor *strokeColor;//描邊顏色
  • @property (nonatomic, assign) BOOL isDash;//YES = 虛線/NO = 實線
  • @property (nonatomic, assign) NSInteger strokeWeight;//描邊寬度

 

 
接下來讓我們看看整體代碼是如何實現的,以及最后的效果是怎樣的:

MGLShape+PolygonParamer.h

  1.  
    //
  2.  
    // MGLShape+PolygonParamer.h
  3.  
    // Etoury
  4.  
    //
  5.  
    // Created by dev on 2018/1/3.
  6.  
    // Copyright © 2018年 iron. All rights reserved.
  7.  
    //
  8.  
     
  9.  
    #import <Mapbox/Mapbox.h>
  10.  
     
  11.  
    @interface MGLShape (PolygonParamer)
  12.  
     
  13.  
     
  14.  
     
  15.  
    @property (nonatomic, strong) UIColor *fillColor;//填充顏色
  16.  
    @property (nonatomic, assign) CGFloat fillOpacity;//填充透明度
  17.  
    @property (nonatomic, strong) UIColor *strokeColor;//描邊顏色
  18.  
    @property (nonatomic, assign) BOOL isDash;//YES = 虛線/NO = 實線
  19.  
    @property (nonatomic, assign) NSInteger strokeWeight;//描邊寬度
  20.  
     
  21.  
     
  22.  
     
  23.  
     
  24.  
    @end

MGLShape+PolygonParamer.h

  1.  
    //
  2.  
    // MGLShape+PolygonParamer.m
  3.  
    // Etoury
  4.  
    //
  5.  
    // Created by dev on 2018/1/3.
  6.  
    // Copyright © 2018年 iron. All rights reserved.
  7.  
    //
  8.  
     
  9.  
    #import "MGLShape+PolygonParamer.h"
  10.  
    #import <objc/runtime.h>
  11.  
     
  12.  
     
  13.  
    static UIColor *_fillColor;//填充顏色
  14.  
    static NSInteger _fillOpacity;//填充透明度
  15.  
    static UIColor *_strokeColor;//描邊顏色
  16.  
    static BOOL _isDash;//YES = 虛線/NO = 實線
  17.  
    static NSInteger _strokeWeight;//描邊寬度
  18.  
     
  19.  
     
  20.  
     
  21.  
    @implementation MGLShape (PolygonParamer)
  22.  
     
  23.  
     
  24.  
    - ( void)setFillColor:(UIColor *)fillColor {
  25.  
    objc_setAssociatedObject( self, &_fillColor, fillColor, OBJC_ASSOCIATION_COPY);
  26.  
    }
  27.  
    - ( UIColor *)fillColor {
  28.  
    return objc_getAssociatedObject(self, &_fillColor);
  29.  
    }
  30.  
     
  31.  
     
  32.  
    - ( void)setFillOpacity:(CGFloat)fillOpacity {
  33.  
    NSNumber *fillOpacityNumber = @(fillOpacity);
  34.  
    objc_setAssociatedObject( self, &_fillOpacity, fillOpacityNumber, OBJC_ASSOCIATION_COPY);
  35.  
    }
  36.  
    - ( CGFloat)fillOpacity {
  37.  
    NSNumber *fillOpacityNumber = objc_getAssociatedObject(self, &_fillOpacity);
  38.  
    return [fillOpacityNumber floatValue];
  39.  
    }
  40.  
     
  41.  
     
  42.  
    - ( void)setStrokeColor:(UIColor *)strokeColor {
  43.  
    objc_setAssociatedObject( self, &_strokeColor, strokeColor, OBJC_ASSOCIATION_COPY);
  44.  
    }
  45.  
    - ( UIColor *)strokeColor {
  46.  
    return objc_getAssociatedObject(self, &_strokeColor);
  47.  
    }
  48.  
     
  49.  
     
  50.  
    - ( void)setIsDash:(BOOL)isDash {
  51.  
    NSNumber *isDashNumber = [NSNumber numberWithBool:isDash];
  52.  
    objc_setAssociatedObject( self, &_isDash, isDashNumber, OBJC_ASSOCIATION_COPY);
  53.  
    }
  54.  
    - ( BOOL)isDash {
  55.  
    NSNumber *isDashNumber = objc_getAssociatedObject(self, &_isDash);
  56.  
    return [isDashNumber boolValue];
  57.  
    }
  58.  
     
  59.  
     
  60.  
    - ( void)setStrokeWeight:(NSInteger)strokeWeight {
  61.  
    NSNumber *strokeWeightNumber = @(strokeWeight);
  62.  
    objc_setAssociatedObject( self, &_strokeWeight, strokeWeightNumber, OBJC_ASSOCIATION_COPY);
  63.  
    }
  64.  
    - ( NSInteger)strokeWeight {
  65.  
    NSNumber *strokeWeightNumber = objc_getAssociatedObject(self, &_strokeWeight);
  66.  
    return [strokeWeightNumber integerValue];
  67.  
    }
  68.  
     
  69.  
     
  70.  
     
  71.  
     
  72.  
    @end

把 MGLShape+PolygonParamer引入到 view controller 中:
  1.  
    //
  2.  
    // LinePolygonMapboxViewController.m
  3.  
    // MapboxExample
  4.  
    //
  5.  
    // Created by iron on 2018/1/30.
  6.  
    // Copyright © 2018年 wangzhengang. All rights reserved.
  7.  
    //
  8.  
     
  9.  
    #import "LinePolygonMapboxViewController.h"
  10.  
    #import <Mapbox/Mapbox.h>
  11.  
    #import "MGLShape+PolygonParamer.h"
  12.  
     
  13.  
     
  14.  
    @interface LinePolygonMapboxViewController ()<MGLMapViewDelegate>
  15.  
    @property (nonatomic, strong) MGLMapView *mapView;
  16.  
     
  17.  
    @property (nonatomic, strong) MGLPolyline *blueLine;//藍色線段
  18.  
     
  19.  
    @property (nonatomic, strong) MGLPolyline *strokeLine;//多邊形邊線
  20.  
    @property (nonatomic, strong) MGLPolygon *polygon;//多邊形
  21.  
     
  22.  
    @end
  23.  
     
  24.  
    @implementation LinePolygonMapboxViewController
  25.  
     
  26.  
    - ( void)dealloc {
  27.  
    [_mapView removeFromSuperview];
  28.  
    _mapView.delegate = nil;
  29.  
    _mapView = nil;
  30.  
    }
  31.  
     
  32.  
    - ( void)viewDidLoad {
  33.  
    [ super viewDidLoad];
  34.  
     
  35.  
    self.title = @"線段和多邊形";
  36.  
     
  37.  
    [ self.view addSubview:self.mapView];
  38.  
    }
  39.  
     
  40.  
    - ( void)didReceiveMemoryWarning {
  41.  
    [ super didReceiveMemoryWarning];
  42.  
    // Dispose of any resources that can be recreated.
  43.  
    }
  44.  
     
  45.  
    - (MGLMapView *)mapView {
  46.  
    if (_mapView == nil) {
  47.  
    //設置地圖的 frame 和 地圖個性化樣式
  48.  
    _mapView = [[MGLMapView alloc] initWithFrame: self.view.bounds styleURL:[NSURL URLWithString:@"mapbox://styles/mapbox/streets-v10"]];
  49.  
    _mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
  50.  
    //設置地圖默認顯示的地點和縮放等級
  51.  
    [_mapView setCenterCoordinate: CLLocationCoordinate2DMake(39.980528, 116.306745) zoomLevel:8 animated:YES];
  52.  
    //顯示用戶位置
  53.  
    _mapView.showsUserLocation = YES;
  54.  
    //定位模式
  55.  
    _mapView.userTrackingMode = MGLUserTrackingModeNone;
  56.  
    //是否傾斜地圖
  57.  
    _mapView.pitchEnabled = YES;
  58.  
    //是否旋轉地圖
  59.  
    _mapView.rotateEnabled = NO;
  60.  
    //代理
  61.  
    _mapView.delegate = self;
  62.  
    }
  63.  
    return _mapView;
  64.  
    }
  65.  
     
  66.  
     
  67.  
    - (MGLPolyline *)blueLine {
  68.  
    if (_blueLine == nil) {
  69.  
    CLLocationCoordinate2D coords[3];
  70.  
    coords[ 0] = CLLocationCoordinate2DMake(27.000, 95.356745);
  71.  
    coords[ 1] = CLLocationCoordinate2DMake(20.000, 105.356745);
  72.  
    coords[ 2] = CLLocationCoordinate2DMake(27.000, 115.356745);
  73.  
     
  74.  
    _blueLine = [MGLPolyline polylineWithCoordinates:coords count: 3];
  75.  
    _blueLine.strokeColor = [ UIColor blueColor];
  76.  
    _blueLine.strokeWeight = 3.f;
  77.  
    _blueLine.fillOpacity = 0.75f;
  78.  
    _blueLine.isDash = NO;
  79.  
    }
  80.  
    return _blueLine;
  81.  
    }
  82.  
     
  83.  
    - (MGLPolyline *)strokeLine {
  84.  
    if (_strokeLine == nil) {
  85.  
    CLLocationCoordinate2D coords[6];
  86.  
    coords[ 0] = CLLocationCoordinate2DMake(30.980528, 110.306745);
  87.  
    coords[ 2] = CLLocationCoordinate2DMake(30.000, 120.306745);
  88.  
    coords[ 1] = CLLocationCoordinate2DMake(40.000, 120.306745);
  89.  
    coords[ 3] = CLLocationCoordinate2DMake(40.000, 110.306745);
  90.  
    coords[ 4] = CLLocationCoordinate2DMake(35.000, 95.356745);
  91.  
    coords[ 5] = CLLocationCoordinate2DMake(30.980528, 110.306745);;
  92.  
    _strokeLine = [MGLPolyline polylineWithCoordinates:coords count: 6];
  93.  
    _strokeLine.strokeColor = [ UIColor blackColor];
  94.  
    _strokeLine.strokeWeight = 2.f;
  95.  
    _strokeLine.fillOpacity = 0.75f;
  96.  
    _strokeLine.isDash = YES;
  97.  
    }
  98.  
    return _strokeLine;
  99.  
    }
  100.  
     
  101.  
    - (MGLPolygon *)polygon {
  102.  
    if (_polygon == nil) {
  103.  
    CLLocationCoordinate2D coords[6];
  104.  
    coords[ 0] = CLLocationCoordinate2DMake(30.980528, 110.306745);
  105.  
    coords[ 2] = CLLocationCoordinate2DMake(30.000, 120.306745);
  106.  
    coords[ 1] = CLLocationCoordinate2DMake(40.000, 120.306745);
  107.  
    coords[ 3] = CLLocationCoordinate2DMake(40.000, 110.306745);
  108.  
    coords[ 4] = CLLocationCoordinate2DMake(35.000, 95.356745);
  109.  
    _polygon = [MGLPolygon polygonWithCoordinates:coords count: 5];
  110.  
    _polygon.fillColor = [ UIColor redColor];
  111.  
    _polygon.strokeColor = [ UIColor blueColor];
  112.  
    _polygon.strokeWeight= 2.f;
  113.  
    _polygon.fillOpacity = 0.5f;
  114.  
    }
  115.  
    return _polygon;
  116.  
    }
  117.  
     
  118.  
    #pragma mark MGLMapViewDelegate
  119.  
    - ( void)mapViewDidFinishLoadingMap:(MGLMapView *)mapView {
  120.  
    ///地圖加載完成后繪制 線段 和 多邊形
  121.  
    [mapView addOverlays:@[ self.blueLine, self.strokeLine, self.polygon]];
  122.  
    ///把窗口顯示到合適的范圍
  123.  
    [mapView setVisibleCoordinateBounds: self.polygon.overlayBounds edgePadding:UIEdgeInsetsMake(0, 10, 200, 10) animated:YES];
  124.  
     
  125.  
    // [mapView setVisibleCoordinateBounds:self.line.overlayBounds edgePadding:UIEdgeInsetsMake(300, 10, 0, 10) animated:YES];
  126.  
    }
  127.  
     
  128.  
    - ( CGFloat)mapView:(MGLMapView *)mapView alphaForShapeAnnotation:(MGLShape *)annotation {
  129.  
    ///MGLPolyline 和 MGLPolygon 都執行這個方法
  130.  
    return annotation.fillOpacity;
  131.  
    }
  132.  
     
  133.  
    - ( UIColor *)mapView:(MGLMapView *)mapView strokeColorForShapeAnnotation:(MGLShape *)annotation {
  134.  
    ///MGLPolyline 和 MGLPolygon 都執行這個方法
  135.  
    if ([@"MGLPolyline" isEqualToString:NSStringFromClass([annotation class])]) {
  136.  
     
  137.  
    if (annotation.isDash) {
  138.  
    MGLShapeSource *shapeSource = [ self addSourceWithShape:annotation];
  139.  
    [ self.mapView.style addSource:shapeSource];
  140.  
    MGLStyleLayer *styleLayer = [ self dashedLineWithStyle:shapeSource shape:annotation lineDashPattern:@[@2.f, @1.f] lineCap:MGLLineCapButt lineColor:[UIColor blackColor] lineWidth:@2];
  141.  
    [ self.mapView.style addLayer:styleLayer];
  142.  
    return [UIColor clearColor];
  143.  
    } else {
  144.  
    return annotation.strokeColor;
  145.  
    }
  146.  
    } else if ([@"MGLPolygon" isEqualToString:NSStringFromClass([annotation class])]) {
  147.  
     
  148.  
    return annotation.strokeColor;
  149.  
    }
  150.  
    return annotation.strokeColor;
  151.  
    }
  152.  
     
  153.  
    - ( UIColor *)mapView:(MGLMapView *)mapView fillColorForPolygonAnnotation:(MGLPolygon *)annotation {
  154.  
    /// MGLPolygon 執行這個方法, MGLPolyline 不執行這個方法
  155.  
    return annotation.fillColor;
  156.  
    }
  157.  
     
  158.  
    - ( CGFloat)mapView:(MGLMapView *)mapView lineWidthForPolylineAnnotation:(MGLPolyline *)annotation {
  159.  
    ///MGLPolyline 執行這個方法, MGLPolygon 不執行
  160.  
    return annotation.strokeWeight;
  161.  
    }
  162.  
     
  163.  
    #pragma mark 畫虛線
  164.  
    - (MGLShapeSource *)addSourceWithShape:(MGLShape *)shape {
  165.  
    return [[MGLShapeSource alloc] initWithIdentifier:@"DashLines" shape:shape options:nil];
  166.  
    }
  167.  
     
  168.  
    - (MGLStyleLayer *)dashedLineWithStyle:(MGLShapeSource *)shapeSource shape:(MGLShape *)shape lineDashPattern:( NSArray<NSNumber *> *)lineDashPattern lineCap:(MGLLineCap)cap lineColor:(UIColor *)lineColor lineWidth:(NSNumber *)lineWidth {
  169.  
    MGLLineStyleLayer *lineStyleLayer = [[MGLLineStyleLayer alloc] initWithIdentifier: @"DashLines" source:shapeSource];
  170.  
    //線段模型
  171.  
    lineStyleLayer.lineDashPattern = [MGLStyleValue valueWithRawValue:lineDashPattern];
  172.  
    //線段頭部
  173.  
    lineStyleLayer.lineCap = [MGLStyleValue valueWithRawValue:[ NSNumber numberWithInteger:cap]];
  174.  
    //線段顏色
  175.  
    lineStyleLayer.lineColor = [MGLStyleValue valueWithRawValue:lineColor];
  176.  
    //線段寬度
  177.  
    lineStyleLayer.lineWidth = [MGLStyleValue valueWithRawValue:lineWidth];
  178.  
    return lineStyleLayer;
  179.  
    }
  180.  
     
  181.  
     
  182.  
     
  183.  
     
  184.  
     
  185.  
    @end
整個代碼的是用步驟是這樣的:
  • 實現 MGLShape (PolygonParamer) 擴展類 MGLShape+PolygonParamer ;
  • 把 MGLShape+PolygonParamer.h 引入到  LinePolygonMapboxViewController.h 這個 view controller 中;
  • 運行看效果;




三、后續更新:

現在文章到這里只是講述了 Mapbox 的常規使用,后續我會更新關於 多點聚合、位置方向等的使用。。。
 

四、和其他地圖的對比:

 

 

五、項目代碼地址:

 

項目示例代碼在GitHub上的地址: https://github.com/wangzhengang/MapboxExample/  
如果您覺得對您有用,請在GitHub上給個星星。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM