地图系列之四 导航划线

简介

  1. 什么是导航划线?
  2. 简单来说, 就是根据用户指定的位置, 进行路线规划; 然后根据用户在行走过程中, 实时的给出指引提示
  3. 导航的三种实现方案:
    1. 可以将需要导航的位置丢给系统的地图APP进行导航
    2. 发送网络请求到公司服务器获取导航数据, 然后自己手动绘制导航(基本没人使用)
    3. 利用三方SDK实现导航(百度)
  4. 怎么使用MapKit在应用中自己划线?

导航画线

使用MapKit自己划线

  1. 使用MKDirections获取导航路线信息

     // 方向对象
     MKDirections *directions = [[MKDirections alloc] initWithRequest:request];
        
     // 计算路线
     [directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) {
         NSLog(@"总共=====%d条路线", response.routes.count);
         }
     }];
    
  2. 绘制路线,添加覆盖层等

      /**
      注意:这里不像添加大头针那样,只要我们添加了大头针模型,默认就会在地图上添加系统的大头针视图
      添加覆盖层,需要我们实现对应的代理方法,在代理方法中返回对应的覆盖层
      */
     [self.mapView addOverlay:overlay];
     调用了以上方法后,会调用以下代理方法获取对应的渲染涂层
     -(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
    
  3. 具体代码举例

     #import "ViewController.h"
     #import <MapKit/MapKit.h>
     #import <CoreLocation/CoreLocation.h>
     #import "ZHAnnotation.h"
     @interface ViewController ()<MKMapViewDelegate>
     @property (weak, nonatomic) IBOutlet MKMapView *mapView;
     @property (nonatomic,strong) CLLocationManager *locationManager;
     @property (nonatomic, strong) CLGeocoder *geocoder;
     @end
        
     @implementation ViewController
     -(CLLocationManager *)locationManager{
         if (_locationManager == nil) {
             _locationManager = [[CLLocationManager alloc] init];
         }
         return _locationManager ;
     }
        
     - (CLGeocoder *)geocoder
     {
         if (!_geocoder) {
             self.geocoder = [[CLGeocoder alloc] init];
         }
         return _geocoder;
     }
        
     - (void)viewDidLoad {
         [super viewDidLoad];
         //请求定位iOS8.0+
         [self.locationManager requestWhenInUseAuthorization];
         [self.locationManager requestAlwaysAuthorization];
        
         //设置地图代理
         self.mapView.delegate = self;
            
         NSString *address1 = @"北京";
         NSString *address2 = @"广州";
         //地理编码出2个位置
         [self.geocoder geocodeAddressString:address1 completionHandler:^(NSArray *placemarks, NSError *error) {
             if (error) return;
                
             CLPlacemark *fromPm = [placemarks firstObject];
                
             [self.geocoder geocodeAddressString:address2 completionHandler:^(NSArray *placemarks, NSError *error) {
                 if (error) return;
                    
                 CLPlacemark *toPm = [placemarks firstObject];
                    
                 [self addLineFrom:fromPm to:toPm];
             }];
         }];
     }
        
     /**
      *  添加导航的线路
      *
      *  @param fromPm 起始位置
      *  @param toPm   结束位置
      */
     - (void)addLineFrom:(CLPlacemark *)fromPm to:(CLPlacemark *)toPm{
            
         // 1.根据编码的位置添加2个大头针
         ZHAnnotation *fromAnno = [[ZHAnnotation alloc] init];
         fromAnno.coordinate = fromPm.location.coordinate;
         fromAnno.title = fromPm.name;
         [self.mapView addAnnotation:fromAnno];
            
         ZHAnnotation *toAnno = [[ZHAnnotation alloc] init];
         toAnno.coordinate = toPm.location.coordinate;
         toAnno.title = toPm.name;
         [self.mapView addAnnotation:toAnno];
            
            
         /*******核心代码*********/
         // 2.查找路线
            
         // 方向请求
         MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init];
         // 设置起点
         MKPlacemark *sourcePm = [[MKPlacemark alloc] initWithPlacemark:fromPm];
         request.source = [[MKMapItem alloc] initWithPlacemark:sourcePm];
            
         // 设置终点
         MKPlacemark *destinationPm = [[MKPlacemark alloc] initWithPlacemark:toPm];
         request.destination = [[MKMapItem alloc] initWithPlacemark:destinationPm];
            
         // 方向对象
         MKDirections *directions = [[MKDirections alloc] initWithRequest:request];
            
         // 计算路线
         [directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) {
             NSLog(@"总共=====%d条路线", response.routes.count);
                
             // 遍历所有的路线
             for (MKRoute *route in response.routes) {
                 // 添加路线遮盖(就回调用下面的代理方法)
                 /*
                  注意:这里不像添加大头针那样,只要我们添加了大头针模型,默认就会在地图上添加系统的大头针视图
                  添加覆盖层,需要我们实现对应的代理方法,在代理方法中返回对应的覆盖层
                  */
                 [self.mapView addOverlay:route.polyline];
             }
         }];
     }
        
     #pragma mark - MKMapViewDelegate
     /*
      Overlay: 遮盖的意思
      跟这个方法很相似(根据模型返回大头针视图)
      - (nullable MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation;
      那么这个方法就是根据overlay模型来返回遮盖
      MKPolyline系统自带的overlay模型
      */
     - (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
     {
         MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithOverlay:overlay];
         renderer.strokeColor = [UIColor redColor];
         return renderer;
     }
     @end
    

使用系统自带的地图app导航

  1. 额外补充2个功能(跟系统app地图导航无关!!!)
    1. 3D视图
    2. 地图截屏
    3. POI检索: 即搜索附近的小吃等
  2. 代码举例

     #import "ViewController.h"
     #import <MapKit/MapKit.h>
     #import <CoreLocation/CoreLocation.h>
     #import "ZHAnnotation.h"
     @interface ViewController ()<MKMapViewDelegate>
     @property (weak, nonatomic) IBOutlet MKMapView *mapView;
     @property (nonatomic,strong) CLLocationManager *locationManager;
     @property (nonatomic, strong) CLGeocoder *geocoder;
     @property (weak, nonatomic) IBOutlet UIImageView *snapshootImageView;
     @end
        
     @implementation ViewController
     -(CLLocationManager *)locationManager{
         if (_locationManager == nil) {
             _locationManager = [[CLLocationManager alloc] init];
         }
         return _locationManager ;
     }
        
     - (CLGeocoder *)geocoder
     {
         if (!_geocoder) {
             self.geocoder = [[CLGeocoder alloc] init];
         }
         return _geocoder;
     }
     - (void)viewDidLoad {
         [super viewDidLoad];
         //请求定位iOS8.0+
         [self.locationManager requestWhenInUseAuthorization];
         [self.locationManager requestAlwaysAuthorization];
            
         //设置地图代理
         self.mapView.delegate = self;
            
            
     }
     //开始使用自带app进行导航
     - (IBAction)startNav:(id)sender {
         NSString *address1 = @"北京";
         //地理编码出目的位置
         [self.geocoder geocodeAddressString:address1 completionHandler:^(NSArray *placemarks, NSError *error) {
             if (error) return;
                
             CLPlacemark *toPm = [placemarks firstObject];
                
             [self beginNavEndPlacemark:toPm];
         }];
     }
     //3D视图
     - (IBAction)DView:(id)sender {
         // 创建视角中心坐标
         CLLocationCoordinate2D center = CLLocationCoordinate2DMake(23.132931, 113.375924);
         // 创建3D视角
         MKMapCamera *camera = [MKMapCamera cameraLookingAtCenterCoordinate:center fromEyeCoordinate:CLLocationCoordinate2DMake(center.latitude + 0.001, center.longitude + 0.001) eyeAltitude:1];
         // 设置到地图上显示
         self.mapView.camera = camera;
        
     }
     //截屏
     - (IBAction)snipPic:(id)sender {
         // 截图附加选项
         MKMapSnapshotOptions *options = [[MKMapSnapshotOptions alloc] init];
         // 设置截图区域(在地图上的区域,作用在地图)
         options.region = self.mapView.region;
         //    options.mapRect = self.mapView.visibleMapRect;
            
         // 设置截图后的图片大小(作用在输出图像)
         options.size = self.mapView.frame.size;
         // 设置截图后的图片比例(默认是屏幕比例, 作用在输出图像)
         options.scale = [[UIScreen mainScreen] scale];
            
         MKMapSnapshotter *snapshotter = [[MKMapSnapshotter alloc] initWithOptions:options];
         [snapshotter startWithCompletionHandler:^(MKMapSnapshot * _Nullable snapshot, NSError * _Nullable error) {
             if (error) {
                 NSLog(@"截图错误:%@",error.localizedDescription);
             }else
             {
                 // 设置屏幕上图片显示
                 self.snapshootImageView.image = snapshot.image;
                 // 将图片保存到指定路径(此处是桌面路径,需要根据个人电脑不同进行修改)
                 NSData *data = UIImagePNGRepresentation(snapshot.image);
                 [data writeToFile:@"/Users/wangshunzi/Desktop/snap.png" atomically:YES];
             }
         }];
        
     }
     /*
      POI检索: 即搜索附近的小吃等
      */
     - (IBAction)POIsearch:(id)sender {
         MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
         request.naturalLanguageQuery = @"小吃";
         request.region = self.mapView.region;
         MKLocalSearch *search=  [[MKLocalSearch alloc] initWithRequest:request];
         [search startWithCompletionHandler:^(MKLocalSearchResponse * _Nullable response, NSError * _Nullable error) {
             NSArray *items = response.mapItems;
             for (MKMapItem *item in items) {
                 NSLog(@"%@===%@",item.name,item.url);
             }
         }];
     }
    
     // 根据两个地标对象进行调用系统导航
     - (void)beginNavEndPlacemark:(CLPlacemark *)endPlacemark
     {
         // 创建起点:当前位置为起点
          MKMapItem *currentLocation = [MKMapItem mapItemForCurrentLocation];
            
         // 创建终点:根据 CLPlacemark 地标对象创建 MKPlacemark 地标对象
         MKPlacemark *itemP2 = [[MKPlacemark alloc] initWithPlacemark:endPlacemark];
         MKMapItem *item2 = [[MKMapItem alloc] initWithPlacemark:itemP2];
            
         NSDictionary *launchDic = @{
                                     // 设置导航模式参数
                                     MKLaunchOptionsDirectionsModeKey : MKLaunchOptionsDirectionsModeDriving,
                                     // 设置地图类型
                                     MKLaunchOptionsMapTypeKey : @(MKMapTypeHybridFlyover),
                                     // 设置是否显示交通
                                     MKLaunchOptionsShowsTrafficKey : @(YES),
                                        
                                     };
         //核心代码!!!!!!!!
         // 根据 MKMapItem 数组 和 启动参数字典 来调用系统地图进行导航
         [MKMapItem openMapsWithItems:@[currentLocation, item2] launchOptions:launchDic];
     }
        
     @end
    

Demo地址

Table of Contents