• 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上给个星星。
  • 相关阅读:
    androidlayout_weight的使用
    软件开发中的真理.
    apk,task,android:process与android:sharedUserId的区别
    WIFI连接
    go simple web server
    echo命令
    shell if
    linux grep命令(包括正则)
    make命令和Makefile文件
    linux中grep命令的用法
  • 原文地址:https://www.cnblogs.com/cg919/p/9336020.html
Copyright © 2020-2023  润新知