iOS核心笔记——MapKit框架(二)

1、导航简介:

✨了解:导航,简单来说,就是根据用户指定的位置,进行路线规划;然后根据用户在行走过程中,实时的给出指引提示。


1-1、iOS导航实现方案:
方案详细说明
方案一 将需要导航的位置传递给系统的地图APP进行导航
方案二 发送网络请求到Apple服务器/公司服务器获取导航数据,然后,手动绘制导航路线
方案三 利用第三方SDK实现导航功能(百度地图)

✨说明:通常如果需要手动绘制导航路线,都是向Apple服务器发送请求、获取导航信息;此处,只对方案一、方案二做详细介绍,方案三将单独说明。


2、系统自带地图APP导航:

✨了解采用逆推法,实现使用Apple系统自带地图进行导航;该方式导航关键在于:[MKMapItem openMapsWithItems:导航路线点 launchOptions:启动参数]


2-1、详细步骤:
步骤详细介绍备注
第一步 设置导航路线的起点、终点,将目标地址地理编码成CLLPlacemark地标对象,根据CLLPlacemark对象创建MKPlacemark对象,MKPlacemark对象在地图上代表每一个点、再根据MKPlacemark对象创建对应的模型,即:MKMapItem对象 MKMapItem
第二步 设置起点、终点模型数组,配置打开系统地图APP启动参数 启动地图应用前相关准备工作
第三步 通过MKMapItem的openMapsWithItems:launchOptions:方法打开系统自带地图进行导航 MKMapItem类方法

✨重要:通过地理编码获取目标位置的CLPlacemark对象,再根据CLPlacemark对象创建MKPlacemark对象;然后,根据MKPlacemark对象创建对应的数据模型对象MKMapItem对象,最后,将所有的导航路线的数据模型对象包装成数组,通过MKMapItem对象的openMapsWithItems:launchOptions:类方法传递给系统自带地图APP;最终,系统自带地图APP根据传入的数据模型对象完成导航操作。


2-2、补充说明:
  • 1、打开系统地图应用时,如果没有设置启动参数,用户进入系统地图之后需要一步一步自主获取导航信息。
  • 2、MKPlacemark继承自CLPlacemark,所以,通过CLPlacemark对象可以创建一个MKPlacemark对象。
  • 3、通过MKMapItem的mapItemForCurrentLocation类方法可以直接获取当前用户所在位置对应的数据模型,但是,需要请求用户定位授权,因为,牵涉到定位用户当前所在位置。
  • 4、使用自带地图APP进行导航的本质:是确定导航路线中要经过的点(CLLPlacemark - - -> MKPlacemark),再将地图上导航所需要用到的地标对象(MKPlacemark)转换成对应的模型(MKMapItem),再将所有的模型通过MKMapItem的openMapsWithItems:launchOptions:类方法传递给系统地图APP,这样就能借助系统地图对指定位置进行导航。
  • 5、使用系统地图APP进行导航核心类:MKMapItem、MKPlacemark。

2-3、示例代码:
 
 1.    // MARK: - 设置起点、终点
 2.    // 1. 将当前位置设置为起点模型
 3.    MKMapItem *beginItem = [MKMapItem mapItemForCurrentLocation];
 4.
 5.    // 2. 设置终点
 6.    [self.geocoder geocodeAddressString:@"长沙" completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
 7.        // 2.1 获取地标对象
 8.        CLPlacemark *clPlacemark = [placemarks firstObject];
 9.
10.        // 2.2 根据CLPlacemark创建MKPlacemark
11.        MKPlacemark *endPlacemark = [[MKPlacemark alloc] initWithPlacemark:clPlacemark];
12.
13.        // 2.3 创建终点模型
14.        MKMapItem *endItem = [[MKMapItem alloc] initWithPlacemark:endPlacemark];
15.
16.        // MARK: - 使用MKMapItem打开系统地图进行导航
17.        // 1. 起点、终点模型数组
18.        NSArray *items = @[beginItem, endItem];
19.
20.        // 2. 设置启动参数
21.        NSDictionary *dict = @{
22.                MKLaunchOptionsDirectionsModeKey : MKLaunchOptionsDirectionsModeDriving,
23.                MKLaunchOptionsMapTypeKey : @(MKMapTypeStandard),
24.                MKLaunchOptionsShowsTrafficKey : @(YES)
25.                               };
26.
27.        // 3. 打开系统地图APP, 进行导航
28.        [MKMapItem openMapsWithItems:items launchOptions:dict];
29.    }];

 

 

3、手动绘制导航路线:

✨了解:想要实现手动绘制导航路线,需要向Apple服务器发送网络请求获取导航路线;需要记住关键对象:导航对象 - - -> MKDirections

✨重要:显示在屏幕上的导航路线也是一个覆盖层,在地图上操作覆盖层,其实操作的是覆盖层的数据模型;删除覆盖层:在地图上移除覆盖层数据模型;添加覆盖层:在地图上添加覆盖层数据模型。


3-1、详细步骤:
步骤详细介绍备注
第一步 创建导航请求对象(MKDirectionsRequest),在该对象中保存有本次导航的起点模型(MKMapItem)、终点模型(MKMapItem),MKDirectionsRequest对象的source、destination属性专门用来保存起点、终点模型 创建请求
第二步 通过导航请求对象创建导航对象(MKDirections) 创建导航对象
第三步 导航对象(MKDirections)调用calculateDirectionsWithCompletionHandler:方法开始向Apple服务器发送请求、获取导航数据信息 获取导航数据
第四步 从Apple服务器获取到导航数据之后开始解析数据(注:导航数据存放在响应体MKDirectionsResponse对象中),从response中便能获取导航路线对象数组、遍历该数组获取导航路线对象(MKRoute)、将导航路线对象中的要显示的渲染图层对应的数据模型添加到mapView中 解析导航数据
第五步 实现返回要显示在mapView上的渲染图层代理方法,在该代理方法中创建渲染图层(MKPolylineRenderer、MKCircleRenderer,具体渲染图层由添加到mapView中的数据模型的类型决定;MKPolyline:折线数据模型,MKCircle:原型数据模型) 返回渲染图层

3-2、详细说明示例图:

✨说明:本质:向Apple服务器发送请求,获取导航数据;获取的导航数据实质是导航路线对象,将导航路线对象中的渲染图层数据模型属性添加到mapView;实现mapView的代理方法,在代理方法中创建渲染图层、并设置相关属性,系统自动将渲染图层添加到mapView上面。


3-3、示例代码:
 1 1.#import "ViewController.h"
 2 2.#import <MapKit/MapKit.h>
 3 3.
 4 4.@interface ViewController () <MKMapViewDelegate>
 5 5./** 地图 */
 6 6.@property (weak, nonatomic) IBOutlet MKMapView *mapView;
 7 7./** 地理编码 */
 8 8.@property (strong, nonatomic) CLGeocoder *geocoder;
 9 9./** 位置管理者对象 */
10 10.@property (strong, nonatomic) CLLocationManager *mgr;
11 11.
12 12.@end
13 13.
14 14.@implementation ViewController
15 15.
16 16.- (void)viewDidLoad {
17 17.    [super viewDidLoad];
18 18.
19 19.    // MARK: - 请求授权
20 20.    self.mgr = [CLLocationManager new];
21 21.    if ([self.mgr respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
22 22.        [self.mgr requestWhenInUseAuthorization];
23 23.    }
24 24.
25 25.    // MARK: - 设置代理
26 26.    self.mapView.delegate = self;
27 27.}
28 28.
29 29.- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
30 30.    // MARK: - 开始导航
31 31.    [self.geocoder geocodeAddressString:@"长沙" completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
32 32.        // 0. 地理编码失败, 返回
33 33.        if (placemarks.count == 0 || error) {
34 34.            NSLog(@"地理编码失败");
35 35.            return ;
36 36.        }
37 37.
38 38.        // MARK: - 创建导航请求对象
39 39.        MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init];
40 40.
41 41.        // MARK: - 设置起点、终点模型
42 42.        // 1. 起点模型, 使用该方式获取当前点对应的数据模型 "需要请求用户定位授权"
43 43.        MKMapItem *beginItem = [MKMapItem mapItemForCurrentLocation];
44 44.        request.source = beginItem;
45 45.
46 46.        // 2. 设置终点
47 47.        CLPlacemark *endCL = placemarks.firstObject;
48 48.        MKPlacemark *endPL = [[MKPlacemark alloc] initWithPlacemark:endCL];
49 49.        MKMapItem *endItem = [[MKMapItem alloc] initWithPlacemark:endPL];
50 50.        request.destination = endItem;
51 51.
52 52.        // 3. 根据MKDirectionsRequest对象, 创建导航对象
53 53.        MKDirections *direction = [[MKDirections alloc] initWithRequest:request];
54 54.
55 55.        // 4. 计算导航路线
56 56.        [direction calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse * _Nullable response, NSError * _Nullable error) {
57 57.
58 58.            if (error != nil) {
59 59.                NSLog(@"导航失败");
60 60.            }
61 61.            NSLog(@"%zd", response.routes.count);
62 62.
63 63.            // 4.1. 遍历导航路线对象数组, MKRoute : 导航路线对象
64 64.            [response.routes enumerateObjectsUsingBlock:^(MKRoute * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
65 65.                // 4.2 将导航路线对象中保存的渲染图层对应的数据模型添加到mapView中
66 66.                [self.mapView addOverlay:obj.polyline];
67 67.            }];
68 68.        }];
69 69.    }];
70 70.}
71 71.
72 72.#pragma mark - <MKMapViewDelegate>
73 73.- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay{
74 74.    // 1. 创建折线渲染图层
75 75.    MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithOverlay:overlay];
76 76.
77 77.    // 2. 设置折线渲染图层相关属性
78 78.    renderer.lineWidth = 10;  // 折线渲染图层折线线宽
79 79.    renderer.strokeColor = [UIColor greenColor];  // 折线渲染图层折线颜色
80 80.
81 81.    // 3. 返回折线渲染图层
82 82.    return renderer;
83 83.}
84 84.
85 85.#pragma mark - 懒加载
86 86.- (CLGeocoder *)geocoder{
87 87.    if (_geocoder == nil) {
88 88.        _geocoder = [[CLGeocoder alloc] init];
89 89.    }
90 90.    return _geocoder;
91 91.}
92 92.@end
 

4、重要类:

4-1、MKDirectionsResponse—响应体对象:
属性名作用
source 导航起点位置模型
destination 导航终点位置模型
routes 导航路线对象数组,数组中存放MKRoute对象

4-2、MKRoute—导航路线对象:
属性名作用
name 导航路线名称
advisoryNotices 导航路线中注意、警告信息
distance 导航路线长度(实际物理距离,单位:m)
polyline 导航路线渲染图层几何形状数据模型(即:该数据模型对应的渲染图层的形状为折线,将来往mapView中添加该类型数据模型时,在代理方法中应当创建折线渲染图层返回)
steps 多个行走步骤组成的数组(例如“前方路口左转”,“保持直行”等等, MKRouteStep 对象)

✨注意:MKRoute是一整条路,MKRouteStep是这条长路中的每一节。


4-3、MKRouteStep—导航步骤对象:
属性名作用
instructions 步骤说明(例如“前方路口左转”,“保持直行”等)
transportType 交通方式(驾车,步行等)
polyline 路线对应的在地图上的几何线路数据模型(由很多点组成,可绘制在地图上)

5、导航渲染图层效果:

5-1、折线渲染图层效果:

示例代码:

 1 1.#import "ViewController.h"
 2 2.#import <MapKit/MapKit.h>
 3 3.
 4 4.@interface ViewController () <MKMapViewDelegate>
 5 5./** 地图 */
 6 6.@property (weak, nonatomic) IBOutlet MKMapView *mapView;
 7 7./** 地理编码 */
 8 8.@property (strong, nonatomic) CLGeocoder *geocoder;
 9 9./** 位置管理者对象 */
10 10.@property (strong, nonatomic) CLLocationManager *mgr;
11 11.@end
12 12.
13 13.@implementation ViewController
14 14.
15 15.- (void)viewDidLoad {
16 16.    [super viewDidLoad];
17 17.
18 18.    // MARK: - 设置代理
19 19.    self.mapView.delegate = self;
20 20.
21 21.    // MARK: - 请求授权
22 22.    self.mgr = [[CLLocationManager alloc] init];
23 23.    if ([self.mgr respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
24 24.        [self.mgr requestWhenInUseAuthorization];
25 25.    }
26 26.}
27 27.
28 28.- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
29 29.    // MARK: - 创建导航请求对象
30 30.    MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init];
31 31.
32 32.    // 1. 设置起点数据模型
33 33.    MKMapItem *beginItem = [MKMapItem mapItemForCurrentLocation];
34 34.
35 35.    // 2. 设置终点数据模型
36 36.    [self.geocoder geocodeAddressString:@"耒阳" completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
37 37.        // 3. 创建MKPlacemark对象
38 38.        CLPlacemark *endCL = placemarks.firstObject;
39 39.        MKPlacemark *endPL = [[MKPlacemark alloc] initWithPlacemark:endCL];
40 40.
41 41.        // 4. 创建终点数据模型
42 42.        MKMapItem *endItem = [[MKMapItem alloc] initWithPlacemark:endPL];
43 43.
44 44.        // 5. 设置为请求对象
45 45.        request.source = beginItem;
46 46.        request.destination = endItem;
47 47.
48 48.        // MARK: - 创建导航对象
49 49.        MKDirections *direcion = [[MKDirections alloc] initWithRequest:request];
50 50.
51 51.        // 1. 计算导航数据
52 52.        [direcion calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse * _Nullable response, NSError * _Nullable error) {
53 53.            // 2. 防错处理
54 54.            if (placemarks.count == 0 || error) {
55 55.                NSLog(@"请求导航错误");
56 56.                return ;
57 57.            }
58 58.
59 59.            // 3. 遍历导航路线对象数组, 将折线渲染图层数据模型添加到mapView
60 60.            [response.routes enumerateObjectsUsingBlock:^(MKRoute * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
61 61.                // 4. 将渲染层数据模型添加mapView
62 62.                [self.mapView addOverlay:obj.polyline];
63 63.            }];
64 64.        }];
65 65.    }];
66 66.}
67 67.
68 68.#pragma mark - <MKMapViewDelegate>
69 69.- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay{
70 70.    // 1. 创建折线渲染图层
71 71.    MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithOverlay:overlay];
72 72.
73 73.    // 2. 设置相关属性
74 74.    renderer.lineWidth = 10;
75 75.    renderer.strokeColor = [UIColor redColor];
76 76.
77 77.    // 3. 返回折线渲染图层
78 78.    return renderer;
79 79.}
80 80.
81 81.#pragma mark - 地理编码
82 82.- (CLGeocoder *)geocoder{
83 83.    if (_geocoder == nil) {
84 84.        _geocoder = [[CLGeocoder alloc] init];
85 85.    }
86 86.    return _geocoder;
87 87.}
88 88.@end

 

 

效果示例图


5-2、圆形渲染图层效果:

示例代码

 1 1.#import "ViewController.h"
 2 2.#import <MapKit/MapKit.h>
 3 3.
 4 4.@interface ViewController () <MKMapViewDelegate>
 5 5./** 地图 */
 6 6.@property (weak, nonatomic) IBOutlet MKMapView *mapView;
 7 7.
 8 8.@end
 9 9.
10 10.@implementation ViewController
11 11.
12 12.- (void)viewDidLoad {
13 13.    [super viewDidLoad];
14 14.
15 15.    // MARK: - 设置mapView的代理
16 16.    self.mapView.delegate = self;
17 17.}
18 18.
19 19.- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
20 20.    // MARK: - 添加圆形渲染图层模型
21 21.    // 1. 圆形渲染图层中心点
22 22.    CLLocationCoordinate2D center = CLLocationCoordinate2DMake(40, 116);
23 23.
24 24.    // 2. 创建圆形渲染图层数据模型
25 25.    MKCircle *circle = [MKCircle circleWithCenterCoordinate:center radius:1000000];
26 26.
27 27.    // 3. 添加到mapView
28 28.    [self.mapView addOverlay:circle];
29 29.}
30 30.
31 31.#pragma mark - <MKMapViewDelegate>
32 32./**
33 33. 当往mapView中添加数据模型时, 便会调用该方法返回对应的渲染图层
34 34.
35 35. @param mapView 地图
36 36. @param overlay 渲染图层模型
37 37. @return 渲染图层
38 38. */
39 39.- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay{
40 40.    // 1. 创建圆形渲染图层
41 41.    MKCircleRenderer *renderer = [[MKCircleRenderer alloc] initWithOverlay:overlay];
42 42.
43 43.    // 2. 设置属性
44 44.    renderer.fillColor = [UIColor greenColor];
45 45.    renderer.alpha = 0.5;
46 46.
47 47.    // 3. 返回圆形渲染图层
48 48.    return renderer;
49 49.}
50 50.@end

 

 

效果示例图

posted @ 2017-02-08 13:29  雷厉峰行  阅读(314)  评论(0编辑  收藏  举报