地图系列之四 导航划线
简介
- 什么是导航划线?
- 简单来说, 就是根据用户指定的位置, 进行路线规划; 然后根据用户在行走过程中, 实时的给出指引提示
- 导航的三种实现方案:
- 可以将需要导航的位置丢给系统的地图APP进行导航
- 发送网络请求到公司服务器获取导航数据, 然后自己手动绘制导航(基本没人使用)
- 利用三方SDK实现导航(百度)
- 怎么使用MapKit在应用中自己划线?
导航画线
使用MapKit自己划线
-
使用
MKDirections
获取导航路线信息// 方向对象 MKDirections *directions = [[MKDirections alloc] initWithRequest:request]; // 计算路线 [directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) { NSLog(@"总共=====%d条路线", response.routes.count); } }];
-
绘制路线,添加覆盖层等
/** 注意:这里不像添加大头针那样,只要我们添加了大头针模型,默认就会在地图上添加系统的大头针视图 添加覆盖层,需要我们实现对应的代理方法,在代理方法中返回对应的覆盖层 */ [self.mapView addOverlay:overlay]; 调用了以上方法后,会调用以下代理方法获取对应的渲染涂层 -(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
-
具体代码举例
#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导航
- 额外补充2个功能(跟系统app地图导航无关!!!)
- 3D视图
- 地图截屏
- POI检索: 即搜索附近的小吃等
-
代码举例
#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