MKMapView 地图

1、创建 MKMapView 地图

  • 在 iOS6 或者 iOS7 中实现这个功能只需要添加地图控件、设置用户跟踪模式、在 mapView:didUpdateUserLocation: 代理方法中设置地图中心区域及显示范围。
  • 在 iOS8+ 中用法稍有不同:
    • a. 由于在地图中进行用户位置跟踪需要使用定位功能,而定位功能在 iOS8 中设计发生了变化,因此必须按照定位中提到的内容进行配置和请求。
    • b. iOS8+ 中不需要进行中心点的指定,默认会将当前位置设置中心点并自动设置显示区域范围。

1.1 配置

  • Objective-C

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 包含头文件
    #import <CoreLocation/CoreLocation.h>
    #import <MapKit/MapKit.h>

    // 遵守协议
    <MKMapViewDelegate, CLLocationManagerDelegate>

    // 声明地图控件
    @property (nonatomic, strong) MKMapView *mapView;

1.2 请求定位

  • Objective-C

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    // 实例化定位管理器
    CLLocationManager *locationManager = [[CLLocationManager alloc] init];
    locationManager.delegate = self;

    // 判断系统定位服务是否开启
    if (![CLLocationManager locationServicesEnabled]) {

    NSLog(@"%@", @"提示:系统定位服务不可用,请开启 !");

    } else {

    // 判断应用定位服务授权状态
    if([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined){ // 没有授权

    // 8.0 及以上系统需手动请求定位授权
    if ([UIDevice currentDevice].systemVersion.doubleValue >= 8.0) {

    // 前台定位,需在 info.plist 里设置 Privacy - Location When In Use Usage Description 的值
    [locationManager requestWhenInUseAuthorization];

    // 前后台同时定位,需在 info.plist 里设置 Privacy - Location Always Usage Description 的值
    // [self.locationManager requestAlwaysAuthorization];
    }

    // 开始定位追踪(第一次打开软件时)
    [locationManager startUpdatingLocation];

    } else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedWhenInUse
    || [CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedAlways) { // 允许定位授权

    // 开始定位追踪
    [locationManager startUpdatingLocation];

    } else{ // 拒绝定位授权

    // 创建警告框(自定义方法)
    NSLog(@"%@", @"提示:当前应用的定位服务不可用,请检查定位服务授权状态 !");
    }
    }

1.3 创建地图

  • Objective-C

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    /*
    mapType:

    MKMapTypeStandard = 0, 标准类型
    MKMapTypeSatellite, 卫星图
    MKMapTypeHybrid 混合类型

    userTrackingMode:用户位置追踪用于标记用户当前位置,此时会调用定位服务,必须先设置定位请求

    MKUserTrackingModeNone = 0, 不跟踪用户位置
    MKUserTrackingModeFollow, 跟踪并在地图上显示用户的当前位置
    MKUserTrackingModeFollowWithHeading, 跟踪并在地图上显示用户的当前位置,地图会跟随用户的前进方向进行旋转
    */

    // 实例化地图控件
    self.mapView = [[MKMapView alloc] initWithFrame:self.view.bounds];
    self.mapView.delegate = self;

    // 设置地图类型
    self.mapView.mapType = MKMapTypeStandard;

    // 设置跟踪模式
    self.mapView.userTrackingMode = MKUserTrackingModeFollow;

    [self.view addSubview:self.mapView];
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    #pragma mark - MKMapViewDelegate 协议方法

    // 更新到用户的位置
    - (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{

    // 只要用户位置改变就调用此方法(包括第一次定位到用户位置),userLocation:是对用来显示用户位置的蓝色大头针的封装

    // 反地理编码
    [[[CLGeocoder alloc] init] reverseGeocodeLocation:userLocation.location
    completionHandler:^(NSArray *placemarks, NSError *error) {

    CLPlacemark *placemark = [placemarks firstObject];

    // 设置用户位置蓝色大头针的标题
    userLocation.title = [NSString stringWithFormat:@"当前位置:%@, %@, %@",
    placemark.thoroughfare, placemark.locality, placemark.country];
    }];

    // 设置用户位置蓝色大头针的副标题
    userLocation.subtitle = [NSString stringWithFormat:@"经纬度:(%lf, %lf)",
    userLocation.location.coordinate.longitude, userLocation.location.coordinate.latitude];

    // 手动设置显示区域中心点和范围

    if ([UIDevice currentDevice].systemVersion.floatValue < 8.0) {

    // 显示的中心
    CLLocationCoordinate2D center = userLocation.location.coordinate;

    // 设置地图显示的中心点
    [self.mapView setCenterCoordinate:center animated:YES];

    // 设置地图显示的经纬度跨度
    MKCoordinateSpan span = MKCoordinateSpanMake(0.023503, 0.017424);

    // 设置地图显示的范围
    MKCoordinateRegion rengion = MKCoordinateRegionMake(center, span);
    [self.mapView setRegion:rengion animated:YES];
    }
    }

    // 地图显示的区域将要改变
    - (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated {

    NSLog(@"区域将要改变:经度:%lf, 纬度:%lf, 经度跨度:%lf, 纬度跨度:%lf",
    mapView.region.center.longitude, mapView.region.center.latitude,
    mapView.region.span.longitudeDelta, mapView.region.span.latitudeDelta);
    }

    // 地图显示的区域改变了
    - (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {

    NSLog(@"区域已经改变:经度:%lf, 纬度:%lf, 经度跨度:%lf, 纬度跨度:%lf",
    mapView.region.center.longitude, mapView.region.center.latitude,
    mapView.region.span.longitudeDelta, mapView.region.span.latitudeDelta);
    }
  • 效果

2、添加大头针

2.1 添加大头针

  • 自定义大头针模型

    • QAnnotation.h

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      #import <MapKit/MapKit.h>

      @interface QAnnotation : NSObject <MKAnnotation>

      @property (nonatomic, copy)NSString *title;
      @property (nonatomic, copy)NSString *subtitle;
      @property (nonatomic, copy)NSString *icon;
      @property (nonatomic, assign)CLLocationCoordinate2D coordinate;

      /// 初始化大头针模型
      + (instancetype)q_annotationWithTitle:(NSString *)title
      subTitle:(NSString *)subTitle
      icon:(NSString *)icon
      coordinate:(CLLocationCoordinate2D)coordinate;

      @end
    • QAnnotation.m

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      @implementation QAnnotation

      /// 初始化大头针模型
      + (instancetype)q_annotationWithTitle:(NSString *)title
      subTitle:(NSString *)subTitle
      icon:(NSString *)icon
      coordinate:(CLLocationCoordinate2D)coordinate{

      QAnnotation *annotation = [[self alloc] init];

      annotation.title = title;
      annotation.subtitle = subTitle;
      annotation.icon = icon;
      annotation.coordinate = coordinate;

      return annotation;
      }

      @end
  • 添加大头针

    • ViewController.m

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      #import "QAnnotation.h"

      // 首先创建 MKMapView 地图

      // 设置大头针显示的内容
      NSString *title = @"xxx大饭店";
      NSString *subtitle = @"全场一律15折,会员20折";
      NSString *icon = @"category_1";

      // 设置大头针放置的位置
      CLLocationCoordinate2D cl2d = CLLocationCoordinate2DMake(40.1020, 116.3265);

      // 初始化大头针模型
      QAnnotation *annotation = [QAnnotation q_annotationWithTitle:title
      subTitle:subtitle
      icon:icon
      coordinate:cl2d];

      // 在地图上添加大头针控件
      [self.mapView addAnnotation:annotation];
    • 效果

2.2 设置大头针样式

  • 设置大头针样式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    // MKMapViewDelegate 协议方法
    - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {

    /*
    显示大头针时触发,返回大头针视图,通常自定义大头针可以通过此方法进行。
    使用遵守协议 <MKAnnotation> 的模型,写此方法时所有遵守协议 <MKAnnotation> 的大头针模型都会改变,不写时为默认样式的大头针。
    */

    // 判断大头针模型是否属于 QAnnotation 类
    if ([annotation isKindOfClass:[QAnnotation class]]) {

    // 显示自定义样式的大头针

    // 获得大头针控件,利用自定义的( QAnnotationView )大头针控件创建
    QAnnotationView *annotationView = [QAnnotationView q_annotationViewWithMapView:mapView];

    // 传递模型,更新大头针数据,覆盖掉之前的旧数据
    annotationView.annotation = annotation;

    return annotationView;

    } else {

    // 显示系统样式的大头针

    // 先从缓存池中取出可以循环利用的大头针控件,利用带针的( MKPinAnnotationView )子类大头针控件创建
    MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:@"qianchia"];

    // 缓存池中没有可以利用的大头针控件
    if (annotationView == nil) {

    // 创建大头针控件
    annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:@"qianchia"];

    // 设置大头针头的颜色
    annotationView.pinColor = MKPinAnnotationColorGreen;

    // 大头针从天而降
    annotationView.animatesDrop = YES;

    // 显示大头针标题和子标题
    annotationView.canShowCallout = YES;

    // 设置子菜单的偏移量
    annotationView.calloutOffset = CGPointMake(0, -10);

    // 自定义子菜单的左右视图
    annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeContactAdd];
    annotationView.leftCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeInfoDark];
    }

    // 传递模型,更新大头针数据,覆盖掉之前的旧数据
    annotationView.annotation = annotation;

    return annotationView;
    }
    }
  • 效果

2.3 不同大头针样式的创建

  • 1、带针的大头针

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    // 先从缓存池中取出可以循环利用的大头针控件,利用带针的( MKPinAnnotationView )子类大头针控件创建
    MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:@"qianchia"];

    // 缓存池中没有可以利用的大头针控件
    if (annotationView == nil) {

    // 创建大头针控件
    annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:@"qianchia"];

    // 设置大头针头的颜色
    annotationView.pinColor = MKPinAnnotationColorGreen;

    // 大头针从天而降
    annotationView.animatesDrop = YES;

    // 显示大头针标题和子标题
    annotationView.canShowCallout = YES;

    // 设置子菜单的偏移量
    annotationView.calloutOffset = CGPointMake(0, -10);

    // 自定义子菜单的左右视图
    annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeContactAdd];
    annotationView.leftCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeInfoDark];
    }

    // 传递模型,更新大头针数据,覆盖掉之前的旧数据
    annotationView.annotation = annotation;

    return annotationView;
    • 效果

  • 2、不带针的大头针

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    // 先从缓存池中取出可以循环利用的大头针控件 利用不带针的( MKAnnotationView )父类大头针控件创建
    MKAnnotationView *annotationView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:@"qianchia"];

    // 缓存池中没有可以利用的大头针控件
    if (annotationView == nil) {

    // 创建大头针控件
    annotationView = [[MKAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:@"qianchia"];

    // 显示大头针标题和子标题
    annotationView.canShowCallout = YES;

    // 设置子菜单的偏移量
    annotationView.calloutOffset = CGPointMake(0, -10);

    // 自定义子菜单的左右视图
    annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeContactAdd];
    annotationView.leftCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeInfoDark];
    }

    // 传递模型,更新大头针数据,覆盖掉之前的旧数据
    annotationView.annotation = annotation;

    // 设置大头针的图片,所有大头针图片相同
    annotationView.image = [UIImage imageNamed:@"category_4"];

    return annotationView;
    • 效果

  • 3、自定义类型的大头针

    • QAnnotationView.h

      1
      2
      3
      4
      5
      6
      @interface QAnnotationView : MKAnnotationView

      /// 创建大头针控件
      + (instancetype)q_annotationViewWithMapView:(MKMapView *)mapView;

      @end
    • QAnnotationView.m

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      #import "QAnnotation.h"
      #import "UIView+Frame.h"

      @interface QAnnotationView ()

      /// 自定义大头针子菜单图片视图
      @property (nonatomic, strong) UIImageView *iconView;

      @end

      @implementation QAnnotationView

      #pragma mark - 创建大头针控件

      /// 创建大头针控件
      + (instancetype)q_annotationViewWithMapView:(MKMapView *)mapView {

      QAnnotationView *annotationView = (QAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:@"qianchia"];

      if (annotationView == nil) {

      annotationView = [[self alloc] initWithAnnotation:nil reuseIdentifier:@"qianchia"];
      }

      return annotationView;
      }

      /// 重写初始化大头针控件方法
      - (instancetype)initWithAnnotation:(id<MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier {

      if (self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier]) {

      // 显示自定义大头针的标题和子标题
      self.canShowCallout = YES;

      // 设置自定义大头针的子菜单左边显示一个图片
      UIImageView *imageView = [[UIImageView alloc] init];
      imageView.bounds = CGRectMake(0, 0, 40, 50);
      self.iconView = imageView;

      // 设置自定义大头针的子菜单左边视图
      self.leftCalloutAccessoryView = self.iconView;
      }
      return self;
      }

      /// 重写大头针模型的 setter 方法
      - (void)setAnnotation:(QAnnotation *)annotation{

      [super setAnnotation:annotation];

      // 设置自定义大头针图片
      self.image = [UIImage imageNamed:annotation.icon];

      // 设置自定义大头针的子菜单图片
      self.iconView.image = [UIImage imageNamed:annotation.icon];
      }

      @end
    • ViewController.m

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      // 判断大头针模型是否属于 QAnnotation 类
      if ([annotation isKindOfClass:[QAnnotation class]]) {

      // 获得大头针控件,利用自定义的( QAnnotationView )大头针控件创建
      QAnnotationView *annotationView = [QAnnotationView q_annotationViewWithMapView:mapView];

      // 传递模型,更新大头针数据,覆盖掉之前的旧数据
      annotationView.annotation = annotation;

      return annotationView;
      }
    • 效果

3、地图画线

  • 设置起点和终点

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    // 获取起点和终点
    NSString *sourceAddress = [alertView textFieldAtIndex:0].text;
    NSString *destinationAddress = [alertView textFieldAtIndex:1].text;

    // 地理编码 起点
    [[[CLGeocoder alloc] init] geocodeAddressString:sourceAddress completionHandler:^(NSArray *placemarks, NSError *error) {

    if (placemarks == nil || error) {
    return;
    } else {

    CLPlacemark *sourcePlacemark = [placemarks firstObject];

    // 移除以前的大头针
    if (self.sourceAnnotation) {
    [self.mapView removeAnnotation:self.sourceAnnotation];
    }

    // 添加新的大头针
    self.sourceAnnotation = [QAnnotation q_annotationWithTitle:sourceAddress
    subTitle:sourcePlacemark.name
    icon:nil
    coordinate:sourcePlacemark.location.coordinate];
    [self.mapView addAnnotation:self.sourceAnnotation];

    // 地理编码 终点
    [[[CLGeocoder alloc] init] geocodeAddressString:destinationAddress completionHandler:^(NSArray *placemarks, NSError *error) {

    if (placemarks == nil || error) {
    return;
    } else {

    CLPlacemark *destinationPlacemark = [placemarks firstObject];

    // 移除以前的大头针
    if (self.destinationAnnotation) {
    [self.mapView removeAnnotation:self.destinationAnnotation];
    }

    // 添加新的大头针
    self.destinationAnnotation = [QAnnotation q_annotationWithTitle:destinationAddress
    subTitle:destinationPlacemark.name
    icon:nil
    coordinate:destinationPlacemark.location.coordinate];
    [self.mapView addAnnotation:self.destinationAnnotation];

    // 开始画线
    [self drawLineWithSourceCLPlacemark:sourcePlacemark destinationCLPlacemark:destinationPlacemark];
    }
    }];
    }
    }];
  • 开始画线

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    // 自定义方法
    - (void)drawLineWithSourceCLPlacemark:(CLPlacemark *)sourceCLPm destinationCLPlacemark:(CLPlacemark *)desinationCLPm{

    // 初始化方向请求
    MKDirectionsRequest *dRequest = [[MKDirectionsRequest alloc] init];

    // 设置起点( CLPlacemark --> MKPlacemark )
    MKPlacemark *sourceMKPm = [[MKPlacemark alloc] initWithPlacemark:sourceCLPm];
    dRequest.source = [[MKMapItem alloc] initWithPlacemark:sourceMKPm];

    // 设置终点( CLPlacemark --> MKPlacemark )
    MKPlacemark *destinationMKPm = [[MKPlacemark alloc] initWithPlacemark:desinationCLPm];
    dRequest.destination = [[MKMapItem alloc] initWithPlacemark:destinationMKPm];

    // 根据请求创建方向
    MKDirections *directions = [[MKDirections alloc] initWithRequest:dRequest];

    // 执行请求
    [directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) {

    if (error) {
    return;
    } else {

    // 移除所有已画的线,移除旧的线
    [self.mapView removeOverlays:self.mapView.overlays];

    for (MKRoute *route in response.routes) {

    // 添加路线,传递路线的遮盖模型数据
    [self.mapView addOverlay:route.polyline];
    }
    }
    }];
    }
  • 设置画线属性

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // MKMapViewDelegate 协议方法
    - (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay{

    MKPolylineRenderer *rederer = [[MKPolylineRenderer alloc] initWithOverlay:overlay];

    rederer.lineWidth = 5; // 设置线宽
    rederer.strokeColor = [UIColor blueColor]; // 设置线的颜色

    return rederer;
    }
  • 效果

4、地图导航

4.1 创建导航

  • 设置起点和终点

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    // 获取起点和终点
    NSString *sourceAddress = [alertView textFieldAtIndex:0].text;
    NSString *destinationAddress = [alertView textFieldAtIndex:1].text;

    // 地理编码 起点
    [[[CLGeocoder alloc] init] geocodeAddressString:sourceAddress completionHandler:^(NSArray *placemarks, NSError *error) {

    if (placemarks == nil || error) {
    return;
    } else {

    CLPlacemark *sourcePlacemark = [placemarks firstObject];

    // 地理编码 终点
    [[[CLGeocoder alloc] init] geocodeAddressString:destinationAddress completionHandler:^(NSArray *placemarks, NSError *error) {

    if (placemarks == nil || error) {
    return;
    } else {

    CLPlacemark *destinationPlacemark = [placemarks firstObject];

    // 开始导航
    [self startNavigationWithSourceCLPlacemark:sourcePlacemark destinationCLPlacemark:destinationPlacemark];
    }
    }];
    }
    }];
  • 开始导航

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    设置导航参数:

    MKLaunchOptionsDirectionsModeKey // 导航模式 Key to a directions mode
    MKLaunchOptionsMapTypeKey // 地图类型 Key to an NSNumber corresponding to a MKMapType
    MKLaunchOptionsShowsTrafficKey // 交通路况 Key to a boolean NSNumber

    // Directions modes
    MKLaunchOptionsDirectionsModeDriving // 驾驶模式
    MKLaunchOptionsDirectionsModeWalking // 步行模式

    // If center and span are present, having a camera as well is undefined
    MKLaunchOptionsMapCenterKey // 地图中心 Key to an NSValue-encoded CLLocationCoordinate2D
    MKLaunchOptionsMapSpanKey // 地图跨度 Key to an NSValue-encoded MKCoordinateSpan
    MKLaunchOptionsCameraKey // 地图相机 Key to MKMapCamera object
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    // 自定义方法
    - (void)startNavigationWithSourceCLPlacemark:(CLPlacemark *)sourceCLPm destinationCLPlacemark:(CLPlacemark *)desinationCLPm{

    if (sourceCLPm == nil || desinationCLPm == nil) {
    return;
    } else {

    // 设置起点( CLPlacemark --> MKPlacemark )
    MKPlacemark *sourceMKPm = [[MKPlacemark alloc] initWithPlacemark:sourceCLPm];
    MKMapItem *sourceItem = [[MKMapItem alloc] initWithPlacemark:sourceMKPm];

    // 设置终点( CLPlacemark --> MKPlacemark )
    MKPlacemark *destinationMKPm = [[MKPlacemark alloc] initWithPlacemark:desinationCLPm];
    MKMapItem *destinationItem = [[MKMapItem alloc] initWithPlacemark:destinationMKPm];

    NSArray *items = @[sourceItem, destinationItem];

    // 设置导航参数(导航模式:驾驶导航,是否显示路况:是,地图类型:标准)
    NSDictionary *options = @{MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving,
    MKLaunchOptionsShowsTrafficKey: @YES,
    MKLaunchOptionsMapTypeKey: @(MKMapTypeStandard)};

    // 打开苹果官方的导航应用(打开苹果自带地图 App 开始导航)
    [MKMapItem openMapsWithItems:items launchOptions:options];
    }
    }
  • 效果

4.2 快速创建导航

  • 从当前位置到指定位置导航

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // 根据“北京市”进行地理编码
    [_geocoder geocodeAddressString:@"北京市" completionHandler:^(NSArray *placemarks, NSError *error) {

    CLPlacemark *clPlacemark = [placemarks firstObject]; // 获取第一个地标
    MKPlacemark *mkplacemark = [[MKPlacemark alloc] initWithPlacemark:clPlacemark]; // 定位地标转化为地图的地标

    NSDictionary *options = @{MKLaunchOptionsMapTypeKey:@(MKMapTypeStandard)};
    MKMapItem *mapItem = [[MKMapItem alloc] initWithPlacemark:mkplacemark];

    // 调用苹果地图开始导航,从当前位置到指定位置
    [mapItem openInMapsWithLaunchOptions:options];
    }];
    • 效果

  • 从位置 1 到位置 2 导航

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    // 根据“北京市”进行地理编码
    [_geocoder geocodeAddressString:@"北京市" completionHandler:^(NSArray *placemarks, NSError *error) {

    CLPlacemark *clPlacemark1 = [placemarks firstObject];
    MKPlacemark *mkPlacemark1 = [[MKPlacemark alloc] initWithPlacemark:clPlacemark1];

    // 注意地理编码一次只能定位到一个位置,不能同时定位,所在放到第一个位置定位完成回调函数中再次定位
    [_geocoder geocodeAddressString:@"郑州市" completionHandler:^(NSArray *placemarks, NSError *error) {

    CLPlacemark *clPlacemark2 = [placemarks firstObject];
    MKPlacemark *mkPlacemark2 = [[MKPlacemark alloc] initWithPlacemark:clPlacemark2];

    NSDictionary *options = @{MKLaunchOptionsMapTypeKey:@(MKMapTypeStandard)};
    MKMapItem *mapItem1 = [[MKMapItem alloc] initWithPlacemark:mkPlacemark1];
    MKMapItem *mapItem2 = [[MKMapItem alloc] initWithPlacemark:mkPlacemark2];

    // 调用苹果地图开始导航,从 Item1 到 Item2
    [MKMapItem openMapsWithItems:@[mapItem1, mapItem2] launchOptions:options];
    }];
    }];
    • 效果

文章目录
  1. 1. 1、创建 MKMapView 地图
    1. 1.1. 1.1 配置
    2. 1.2. 1.2 请求定位
    3. 1.3. 1.3 创建地图
  2. 2. 2、添加大头针
    1. 2.1. 2.1 添加大头针
    2. 2.2. 2.2 设置大头针样式
    3. 2.3. 2.3 不同大头针样式的创建
  3. 3. 3、地图画线
  4. 4. 4、地图导航
    1. 4.1. 4.1 创建导航
    2. 4.2. 4.2 快速创建导航
隐藏目录