首页 > 代码库 > iOS核心笔记—MapKit框架-基础
iOS核心笔记—MapKit框架-基础
1、MapKit框架简介:
?了解
:MapKit框架使用须知:①、MapKit框架中所有的数据类型的前缀都是MK;②、需要导入#import <MapKit/MapKit.h>
头文件;③、MapKit框架中有一个非常重要的UI控件:MKMapView
,专门用于地图显示,例如:大头针、路线、覆盖层展示等(着重界面展示)。
1-1、地图设置:
1-1-1、设置地图显示类型:
地图类型:
地图枚举 | 地图类型 |
---|---|
MKMapTypeStandard | 普通地图 |
MKMapTypeSatellite | 卫星云图 |
MKMapTypeHybrid | 混合模式(普通地图覆盖于卫星云图之上 ) |
MKMapTypeSatelliteFlyover | 3D立体卫星(iOS9.0) |
MKMapTypeHybridFlyover | 3D立体混合(iOS9.0) |
?备注
:通过MKMapView
的mapType
属性可以设置地图类型,iOS9.0新出的属性在我国不能使用。
1-1-2、设置地图控制项:
地图控制项:
地图控制项 | 地图类型 |
---|---|
mapView.zoomEnabled | 地图是否可以缩放 |
mapView.scrollEnabled | 地图是否可以滚动 |
mapView.rotateEnabled | 地图是否可以旋转 |
mapView.pitchEnabled | 地图是否显示3D效果 |
?备注
:通过设置这些属性,可以控制地图的旋转、缩放、移动等操作行为。
1-1-3、设置地图显示项:
地图显示项:
地图显示项 | 地图类型 |
---|---|
mapView.showsCompass | 是否显示指南针 |
mapView.showsScale | 是否显示比例尺 |
mapView.showsTraffic | 是否显示交通状况 |
mapView.showsBuildings | 是否显示建筑物 |
mapView.showsPointsOfInterest | 是否显示兴趣点 |
mapView.showsUserLocation | 是否显示用户的位置 |
?了解
:地图上的指南针、比例尺、建筑物、POI点都可以控制是否显示。
1-2、使用注意:
?注意-1
:从iOS7.0开始可以不用手动导入框架,使用MapKit框架中的类创建对象时便会隐式的导入MapKit框架;但是,如果是直接从storyboard中拖入MKMapView
控件,则需要手动导入MapKit框架,否则,运行时将报无法正常创建mapView
的错误。?
?注意-2
:加载地图数据需要联网。
2、大头针基本使用:
?重要
:大头针在mapView上显示的任何数据都是由其对应的大头针数据模型所决定的。
2-1、显示用户位置:
1.#import "ViewController.h"
2.#import <MapKit/MapKit.h>
3.
4.@interface ViewController () <MKMapViewDelegate>
5./** 地图控件 */
6.@property (weak, nonatomic) IBOutlet MKMapView *mapView;
7./** 位置管理者对象 */
8.@property (strong, nonatomic) CLLocationManager *mgr;
9.
10.@end
11.
12.@implementation ViewController
13.
14.- (void)viewDidLoad {
15. [super viewDidLoad];
16.
17. // 1. 创建位置管理者对象
18. self.mgr = [CLLocationManager new];
19.
20. // 2. 请求定位授权
21. if ([self.mgr respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
22. [self.mgr requestWhenInUseAuthorization];
23. }
24.
25. // 3. 设置用户跟踪模式, 以便在mapView中显示用户的位置
26.// self.mapView.userTrackingMode = MKUserTrackingModeFollow;
27. self.mapView.userTrackingMode = MKUserTrackingModeFollowWithHeading;
28.
29. // 4. 设置mapView的代理, 监听mapView上用户的移动
30. self.mapView.delegate = self;
31.}
32.
33.#pragma mark - MKMapViewDelegate
34.
35./**
36. mapView中用户位置更新完毕调用
37. */
38.- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{
39. NSLog(@"%@", userLocation.location);
40.}
41.
42.@end
?备注
:显示自定义大头针标题:在mapView代理方法中,结合反地理编码;将大头针模型中的location属性反地理编码,以便获取详细的地标对象(CLPlacemark);再从地标对象中获取具体的位置信息,将具体的位置信息设置到大头针模型属性中,以便大头针展示。这里有几个注意点:①、从大头针数据模型中取出位置对象(CLLocation),再将位置对象进行反地理编码获取包含详细地址信息的地标对象(CLPlacemark);再将地标对象中的详细地址信息设置到大头针数据模型中,将来大头针控件便能将大头针数据模型中的数据显示在mapView上面。
显示用户位置模式:
模式 | 作用 |
---|---|
MKUserTrackingModeNone = 0 | 默认模式, 不显示用户位置 |
MKUserTrackingModeFollow = 1 | 显示用户位置, 无方向箭头; 常用于只需要显示用户位置 |
MKUserTrackingModeFollowWithHeading = 2 | 显示用户位置, 并显示方向箭头; 常用于导航 |
MKUserLocation(模型):
属性 | 作用 |
---|---|
updating | 判断用户位置是否已更新 |
location | 位置对象 |
heading | 设备朝向 |
title | 触摸大头针显示的标题 |
subtitle | 触摸大头针显示的子标题 |
?备注
:MKUserLocation对应的是显示用户位置的“蓝色光圈”大头针数据模型,其所有属性都为readonly
。
2-2、模拟追踪显示用户位置:
?重要
:设置以用户所在位置为mapView中心点,因为,用户当前所在位置相对于mapView来说是固定的(即:不能移动用户的位置到mapView现有显示区域的中心点,移动用户位置至mapView现有显示区域中心点去显示用户位置便没有任何意义);所以,在不移动用户位置的前提下在mapView的显示区域的中心点位置显示用户当前所在位置便需要依靠改变mapView的显示区域来完成。切记:是改变mapView的显示区域,以达到在mapView的中心点位置显示用户位置;千万不要误认为是修改用户的位置。
1.#import "ViewController.h"
2.#import <MapKit/MapKit.h>
3.
4.@interface ViewController () <MKMapViewDelegate>
5./** 地图控件 */
6.@property (weak, nonatomic) IBOutlet MKMapView *mapView;
7./** 位置管理者对象 */
8.@property (strong, nonatomic) CLLocationManager *mgr;
9.
10.@end
11.
12.@implementation ViewController
13.
14.- (void)viewDidLoad {
15. [super viewDidLoad];
16.
17. // 1. 创建位置管理者对象
18. self.mgr = [CLLocationManager new];
19.
20. // 2. 请求定位授权
21. if ([self.mgr respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
22. [self.mgr requestWhenInUseAuthorization];
23. }
24.
25. // 3. 设置用户跟踪模式, 以便在mapView中显示用户的位置
26. self.mapView.userTrackingMode = MKUserTrackingModeFollowWithHeading;
27.
28. // 4. 设置mapView的代理, 监听mapView上用户的移动
29. self.mapView.delegate = self;
30.}
31.
32./**
33. 设置用户当前所在位置为mapView显示区域中心点坐标
34. mapView显示区域 : 当前展示在手机屏幕中的区域即为显示区域
35. */
36.- (IBAction)backMapCenter:(UIButton *)sender {
37. // MARK: - 方式一 : 设置mapView的centerCoordinate属性,
38. // 只能改变mapView中心点坐标, 无法改变跨度
39.// self.mapView.centerCoordinate = self.mapView.userLocation.location.coordinate;
40. // 带动画的方式
41. [self.mapView setCenterCoordinate:self.mapView.userLocation.location.coordinate animated:YES];
42.
43. // MARK: - 方式二 : 设置mapView的region属性
44. // 能同时改变mapView的中心点位置、显示区域的跨度
45. // 1. 创建显示区域中心点坐标
46. CLLocationCoordinate2D center = self.mapView.userLocation.location.coordinate;
47.
48. // 2. 设置显示区域的跨度
49. MKCoordinateSpan span = MKCoordinateSpanMake(0.01, 0.01);
50.
51. // 3. 动画设置用户位置为mapView中心点位置
52. [self.mapView setRegion:MKCoordinateRegionMake(center, span) animated:YES];
53.}
54.
55./**
56. mapView显示区域会调用该方法, 在该方法中能够获取mapView系统的跨度
57. */
58.- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated{
59. NSLog(@"latitudeDelta : %lf, longitudeDelta : %lf", mapView.region.span.latitudeDelta, mapView.region.span.longitudeDelta);
60.}
61.@end
?说明
:设置用户当前所在位置为中心点的两种方式:①、直接修改mapView的centerCoordinate属性,直接将用户所在位置设置为该属性的值,但是,这种方式一旦修改mapView的显示跨度、用户所在位置之后,虽然能将用户所在位置设置为mapView中心点位置,但是,mapView的显示区域跨度无法还原(即:如果没有手动还原mapView的显示区域跨度,那么,跨度将一直保持在改变之后的值),即:该方式不能合理改变显示跨度;②、设置mapView的region属性,因为region属性包含两个成员center、span,通过设置该属性能够将用户当前所在位置设置为mapView的显示区域中心点位置,而且还能同时设置mapView显示区域的跨度。注意:如果需要动画将用户所在位置设置为mapView的中心点坐标应当使用属性对应的带有动画的set方法,而不是直接设置用户的属性。
?补充
:当mapView的显示区域发生变化后,会调用mapView:regionDidChangeAnimated:代理方法,在该代理方法中可以通过mapView.region.span.longitudeDelta、mapView.region.span.latitudeDelta分别获取系统的经纬度跨度;这样,在我们设置用户当前所在位置为mapView中心点坐标的时候便可以使用系统的跨度,在mapView的中心点坐标修改之后,mapView显示区域的跨度为系统跨度;避免每次修改mapView的中心点坐标的时候导致mapView显示区域的跨度不一致。
2-3、缩放地图:
?了解
:放大、缩小地图,实质是修改mapView的region.span的值;是对应方向上的跨度发生变化。
1./**
2. 放大地图, 实质是减小跨度值
3. */
4.- (IBAction)zoomInClick:(UIButton *)sender {
5. // 1. 修改跨度
6. CLLocationDegrees latitudeDelta = self.mapView.region.span.latitudeDelta * 0.5;
7. CLLocationDegrees longitudeDelta = self.mapView.region.span.longitudeDelta * 0.5;
8.
9. // 2. 重置mapView的region
10. self.mapView.region = MKCoordinateRegionMake(self.mapView.region.center, MKCoordinateSpanMake(latitudeDelta, longitudeDelta));
11.}
12.
13./**
14. 缩小地图, 实质是增大跨度值
15. */
16.- (IBAction)zoomOutClick:(UIButton *)sender {
17. // 1. 修改跨度
18. CLLocationDegrees latitudeDelta = self.mapView.region.span.latitudeDelta * 2;
19. CLLocationDegrees longitudeDelta = self.mapView.region.span.longitudeDelta * 2;
20.
21. // 2. 重置mapView的region
22. self.mapView.region = MKCoordinateRegionMake(self.mapView.region.center, MKCoordinateSpanMake(latitudeDelta, longitudeDelta));
23.}
?步骤
:①、跨度倍数处理;②、重设region属性。
3、自定义大头针:
3-1、自定义大头针数据模型:
?重要
:所有自定义大头针数据模型必须遵守MKAnnotation
协议。
详细步骤:
步骤 | 详细说明 |
---|---|
第一步 | 导入MapKit框架 |
第二步 | 自定义模型类继承自NSObject,遵守MKAnnotation协议 |
第三步 | 拷贝协议中的所有属性, 并删除readonly |
第四步 | 创建自定义大头针数据模型对象 |
第五步 | 自定义大头针数据模型对象添加到mapView中 |
?重要
:为什么要删除readonly?因为,要设置大头针相关属性,如果不删除readonly,那么,大头针数据模型中所有的属性都为只读的,将来使用该模型添加到mapView中时,无法显示数据。
自定义大头针数据模型:
1.#import <Foundation/Foundation.h>
2.#import <MapKit/MapKit.h>
3.
4.@interface MyAnnotationModel : NSObject <MKAnnotation>
5./** 大头针位置 */
6.@property (nonatomic) CLLocationCoordinate2D coordinate;
7./** 大头针标题 */
8.@property (nonatomic, copy, nullable) NSString *title;
9./** 大头针子标题 */
10.@property (nonatomic, copy, nullable) NSString *subtitle;
11.
12.@end
使用自定义大头针数据模型:
1.#import "ViewController.h"
2.#import <MapKit/MapKit.h>
3.#import "MyAnnotationModel.h"
4.
5.@interface ViewController ()
6./** 地图视图 */
7.@property (weak, nonatomic) IBOutlet MKMapView *mapView;
8.
9.@end
10.
11.@implementation ViewController
12.
13.- (void)viewDidLoad {
14. [super viewDidLoad];
15.
16. // 1. 创建大头针数据模型
17. MyAnnotationModel *model = [MyAnnotationModel new];
18.
19. // 2. 设置大头针数据模型属性
20. model.coordinate = CLLocationCoordinate2DMake(40, 116);
21. model.title = @"帝都";
22. model.subtitle = @"充满魅力的城市";
23.
24. // 3. 添加到mapView
25. [self.mapView addAnnotation:model];
26.}
27.
28.- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
29. // 1. 获取触摸点坐标
30. CGPoint point = [[touches anyObject] locationInView:self.mapView];
31.
32. // 2. 将点转换为经纬度
33. CLLocationCoordinate2D coordinate = [self.mapView convertPoint:point toCoordinateFromView:self.mapView];
34.
35. // 3. 创建自定义大头针数据模型
36. MyAnnotationModel *model = [MyAnnotationModel new];
37.
38. // 4. 设置大头针数据模型相关属性
39. model.coordinate = coordinate;
40. model.title = @"圣安东尼奥";
41. model.subtitle = @"诸葛维奇_马刺队";
42.
43. // 5. 添加到mapView
44. [self.mapView addAnnotation:model];
45.}
46.
47.@end
?说明
:注意通过mapView的convertPoint:toCoordinateFromView:方法
能够将触摸在屏幕上的点转换为mapView上面的经纬度。
3-2、自定义大头针视图:
?重要
:与大头针视图相关的类:MKAnnotationView、MKPinAnnotationView;当往mapView中添加“大头针数据模型”时,便会来到mapView的mapView:viewForAnnotation:
代理方法询问代理该“返回大头针视图”;当该代理方法没有实现、或者返回“nil”时,大头针视图默认交由系统自动处理,系统会根据实际需求决定是返回显示用户位置的“蓝色光圈”、或者返回其他样式的大头针视图。
详细步骤:
步骤 | 详细说明 |
---|---|
第一步 | 创建大头针视图静态重用标识 |
第二步 | 从缓存池中查找是否有可重用的大头针视图 |
第三步 | 判断大头针视图是否创建成功,如果创建不成功,则手动创建大头针视图(通常使用MKAnnotationView的子类MKPinAnnotationView创建大头针视图) |
第四步 | 给大头针视图设置属性值(MKPinAnnotationView类才有相关属性) |
第五步 | 返回大头针视图 |
?注意
:在代理方法中,使用MKAnnotationView创建大头针视图并返回;将来mapView中显示大头针视图时,默认不显示,因为,大头针视图没有颜色。
1.#import "ViewController.h"
2.#import <MapKit/MapKit.h>
3.#import "MyAnnotationModel.h"
4.
5.@interface ViewController () <MKMapViewDelegate>
6./** 地图视图 */
7.@property (weak, nonatomic) IBOutlet MKMapView *mapView;
8./** 位置管理者对象 */
9.@property (strong, nonatomic) CLLocationManager *mgr;
10.
11.@end
12.
13.@implementation ViewController
14.
15.- (void)viewDidLoad {
16. [super viewDidLoad];
17.
18. // MARK: - 定位授权
19. // 1. 创建位置管理者对象
20. self.mgr = [CLLocationManager new];
21.
22. // 2. 请求授权, 使用如下形式进行授权操作, 等价于已经做好版本适配操作
23. // 因为, iOS8.0之前, 位置管理者对象没有requestWhenInUseAuthorization方法
24. if ([self.mgr respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
25. [self.mgr requestWhenInUseAuthorization];
26. }
27.
28. // MARK: - 添加大头针
29. // 1. 创建大头针数据模型
30. MyAnnotationModel *model = [MyAnnotationModel new];
31.
32. // 2. 设置大头针数据模型属性
33. model.coordinate = CLLocationCoordinate2DMake(40, 116);
34. model.title = @"帝都";
35. model.subtitle = @"充满魅力的城市";
36.
37. // 3. 添加到mapView
38. [self.mapView addAnnotation:model];
39.
40. // MARK: - 设置mapView相关属性
41. self.mapView.userTrackingMode = MKUserTrackingModeFollow; // 显示用户位置
42. self.mapView.delegate = self; // 设置代理
43.}
44.
45.- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
46. // 1. 获取触摸点坐标
47. CGPoint point = [[touches anyObject] locationInView:self.mapView];
48.
49. // 2. 将点转换为经纬度
50. CLLocationCoordinate2D coordinate = [self.mapView convertPoint:point toCoordinateFromView:self.mapView];
51.
52. // 3. 创建自定义大头针数据模型
53. MyAnnotationModel *model = [MyAnnotationModel new];
54.
55. // 4. 设置大头针数据模型相关属性
56. model.coordinate = coordinate;
57. model.title = @"圣安东尼奥";
58. model.subtitle = @"诸葛维奇_马刺队";
59.
60. // 5. 添加到mapView
61. [self.mapView addAnnotation:model];
62.}
63.
64./**
65. 当mapView添加"大头针数据模型"时, 便会来到该方法返回"大头针视图"
66. 没有实现该代理方法、或者返回为nil, 表示大头针视图类型由系统决定
67.
68. @param mapView 地图视图
69. @param annotation 大头针数据模型
70. @return 大头针视图
71. */
72.- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
73. // 0. 显示系统类型大头针视图
74. if ([annotation isKindOfClass:[MKUserLocation class]]) {
75. // 返回nil, 表示大头针视图类型由系统决定
76. return nil;
77. }
78.
79. // 1. 定义静态重用标识
80. static NSString *ID = @"annotation";
81.
82. // 2. 从缓存池中查找可重用的大头针视图
83. // MKAnnotationView : 该类型大头针视图默认image属性为nil, 不显示
84. // MKPinAnnotationView : 为MKAnnotationView的子类, 默认为红色
85.// MKAnnotationView *annot = [self.mapView dequeueReusableAnnotationViewWithIdentifier:ID];
86. MKPinAnnotationView *pin = (MKPinAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:ID];
87.
88. // 3. 判断缓存池是否有可重用的大头针视图
89. if (pin == nil) {
90. pin = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:ID];
91.
92. // MARK: - 设置大头针视图属性
93. // 1. 设置颜色
94. // pinTintColor : iOS9.0设置大头针视图颜色属性
95. // pinColor : iOS9.0之前设置大头针颜色属性
96. pin.pinTintColor = [UIColor colorWithRed:((float)arc4random_uniform(256) / 255.0) green:((float)arc4random_uniform(256) / 255.0) blue:((float)arc4random_uniform(256) / 255.0) alpha:1.0];
97.
98. // 2. 设置动画掉落
99.// pin.animatesDrop = YES;
100. }
101.
102. // 4. 返回大头针视图
103. return pin;
104.}
105.@end
?注意
:自定义大头针视图时,为避免覆盖显示用户位置“蓝色光圈”;需要对大头针数据模型进行判断:mapView中显示用户位置的“蓝色光圈”也是一种大头针视图,其对应的数据模型类型为:MKUserLocation。所以,当我们实现代理方法返回自定义大头针视图时,一定要对“蓝色光圈”大头针视图进行判断;避免自定义大头针视图覆盖“蓝色光圈”(即:如果在代理方法中未加判断,直接返回自定义大头针视图;将来在mapView中添加“大头针数据模型”时,mapView中显示的所有的大头针视图全都为自定义类型的大头针视图;显示用户位置的“蓝色光圈”也被自定义大头针视图给覆盖)。
?补充-1
:在mapView中,当我们需要显示用户位置时,等价于需要定位当前用户所在位置;所以,在iOS8.0之后需要进行定位授权操作;否则,无法显示用户位置。备注:授权操作两步曲:①、配置plist文件相应的键值对,key为NSLocationWhenInUseUsageDescription/NSLocationAlwaysUsageDescription;②、使用代码请求授权,位置管理者对象调用requestWhenInUseAuthorization/requestAlwaysAuthorization方法请求授权。二者缺一不可。
?补充-2
:MKAnnotationView的image属性可以设置大头针视图的图片,当我们自定义大头针视图时,默认该属性的值为nil。
?补充-3
:自定义大头针视图,使用MKAnnotationView,让大头针视图显示自定义图片,根据MVC思想,在大头针数据模型中新增image属性,在代理方法中,根据大头针数据模型的image属性创建图片并设置为自定义大头针视图的image。注意:一个大头针对应一个大头针数据模型。增加一个大头针视图,只需要增加一个大头针数据模型;删除一个大头针,只需要删除一个大头针数据模型。
4、模拟系统大头针掉落动画效果:
?重要
:自定义大头针视图,并模拟系统大头针掉落动画效果。其原理时在大头针未显示之前将大头针视图移动至屏幕上方外面,然后,再以动画的形式将大头针从屏幕外面移动至屏幕中指定位置;所有操作都在mapView的mapView:didAddAnnotationViews:
方法中完成。模拟系统大头针动画调用效果的本质:是在mapView的代理方法中,动态改变大头针视图的frame。
4-1、详细步骤:
步骤 | 详细说明 |
---|---|
第一步 | 记录大头针在mapView中要显示的位置 |
第二步 | 将大头针视图的frame设置到屏幕外 |
第三步 | 在UIView动画中将大头针视图的frame还原至之前需要显示的位置。注意事项:所有操作必须是在大头针还未显示前的代理方法中执行,在给自定义大头针视图添加掉落动画效果时需要对显示用户位置的“蓝色光圈”大头针进行特殊处理;通过大头针视图对应的大头针数据模型的类型进行区分,避免“蓝色光圈”也带有掉落动画效果。记得要在返回大头针视图的代理方法中设置大头针的image属性 |
4-2、示例代码:
1.#import "ViewController.h"
2.#import "MyAnnotationModel.h"
3.#import "MyAnnotationView.h"
4.
5.#import <MapKit/MapKit.h>
6.
7.@interface ViewController () <MKMapViewDelegate>
8./** 地图视图 */
9.@property (weak, nonatomic) IBOutlet MKMapView *mapView;
10./** 位置管理者对象 */
11.@property (strong, nonatomic) CLLocationManager *mgr;
12.
13.@end
14.
15.@implementation ViewController
16.
17.- (void)viewDidLoad {
18. [super viewDidLoad];
19.
20. // MARK: - 请求授权
21. // 1. 创建位置管理者对象
22. self.mgr = [CLLocationManager new];
23.
24. // 2. 请求授权
25. if ([self.mgr respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
26. [self.mgr requestWhenInUseAuthorization];
27. }
28.
29. // MARK: - 设置mapView属性
30.// self.mapView.userTrackingMode = MKUserTrackingModeFollow;
31. self.mapView.delegate = self;
32.}
33.
34.- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
35. // MARK: - 大头针一
36. MyAnnotationModel *model1 = [MyAnnotationModel new];
37. model1.coordinate = CLLocationCoordinate2DMake(40, 116);
38. model1.title = @"帝都";
39. model1.subtitle = @"充满魔力的城市";
40. model1.icon = @"苍老师";
41. [self.mapView addAnnotation:model1];
42.
43. // MARK: - 大头针二
44. MyAnnotationModel *model2 = [MyAnnotationModel new];
45. model2.coordinate = CLLocationCoordinate2DMake(23, 108);
46. model2.title = @"东莞";
47. model2.subtitle = @"充满美丽的城市";
48. model2.icon = @"自拍照";
49. [self.mapView addAnnotation:model2];
50.}
51.
52.
53.#pragma mark - <MKMapViewDelegate>
54./**
55. 当往mapView中添加数据模型时, 便会来到此代理方法中返回大头针视图
56. 通常在该方法中自定义大头针视图, 该方法返回nil默认大头针视图类型由系统处理
57.
58. @param mapView 地图
59. @param annotation 大头针模型
60. @return 大头针视图
61. */
62.- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
63. // 1. 如果是"蓝色光圈", 则由系统决定
64. if ([annotation isKindOfClass:[MKUserLocation class]]) {
65. return nil;
66. }
67.
68. // 2. 创建大头针视图
69. MyAnnotationView *annotationView = [MyAnnotationView annotationViewWithMapView:mapView];
70.
71. // 3. 返回大头针视图
72. return annotationView;
73.}
74.
75./**
76. 大头针视图还未显示时会调用该方法
77.
78. @param mapView 地图
79. @param views 所有大头针视图
80. */
81.- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray<MKAnnotationView *> *)views{
82. // 如果没有大头针视图, 则直接返回
83. if (views.count == 0) {
84. return ;
85. }
86.
87. // 遍历大头针视图数组, 添加掉落动画
88. for (MKAnnotationView *annotView in views) {
89. // 1. 如果是"蓝色光圈", 则不需要添加动画
90. if ([annotView.annotation isKindOfClass:[MKUserLocation class]]) {
91. continue; // 记住: 此处是使用continue, 因为还需要进行下一次遍历操作
92. }
93.
94. // 2. 记录大头针显示位置
95. CGRect endFrame = annotView.frame;
96.
97. // 3. 改变大头针的frame
98. annotView.frame = CGRectMake(annotView.frame.origin.x, -80, annotView.bounds.size.width, annotView.bounds.size.height);
99.
100. // 4. 动画还原大头针至原定显示位置
101. [UIView animateWithDuration:3.0 animations:^{
102. annotView.frame = endFrame;
103. }];
104. }
105.}
106.
107.@end
5、封装自定义大头针视图:
示例代码一:大头针视图内部实现
1.#import "MyAnnotationView.h"
2.#import "MyAnnotationModel.h"
3.
4.@implementation MyAnnotationView
5.
6.+ (instancetype)annotationViewWithMapView:(MKMapView *)mapView{
7. // 1. 定义静态重用标识
8. static NSString *ID = @"annotationView";
9.
10. // 2. 从缓存池中查找
11. MyAnnotationView *annotationView = (MyAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:ID];
12.
13. // 3. 判断缓存池中是否有可重用的大头针视图
14. if (annotationView == nil) {
15. annotationView = [[MyAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:ID];
16. }
17.
18. // 4. 返回大头针视图
19. return annotationView;
20.}
21.
22./**
23. 无论外界是否有使用到大头针的模型属性, 系统都会自动调用该方法
24. 重写该方法之后, 一定要调用super方法; 否则, 程序直接崩溃
25. */
26.- (void)setAnnotation:(id<MKAnnotation>)annotation{
27. [super setAnnotation:annotation];
28.
29. // 4.1. 设置大头针图片, 一旦自定义大头针视图, image默认为: nil
30. MyAnnotationModel *model = annotation; // 强转
31. self.image = [UIImage imageNamed:model.icon];
32.
33. // 4.2 显示标题/子标题, 自定义大头针视图默认为: NO, 将不显示标题/子标题/辅助视图
34. self.canShowCallout = YES;
35.
36. // 4.3 左右辅助视图
37. self.leftCalloutAccessoryView = [UISwitch new];
38. self.rightCalloutAccessoryView = [UISwitch new];
39.
40. // 4.4 iOS9.0 新增属性: 标题下面可以设置详细视图, 设置该属性之后将会覆盖子标题
41. self.detailCalloutAccessoryView = [UISwitch new];
42.}
43.
44.@end
示例代码二:外界使用:
1.#import "ViewController.h"
2.#import "MyAnnotationModel.h"
3.#import "MyAnnotationView.h"
4.
5.#import <MapKit/MapKit.h>
6.
7.@interface ViewController () <MKMapViewDelegate>
8./** 地图视图 */
9.@property (weak, nonatomic) IBOutlet MKMapView *mapView;
10./** 位置管理者对象 */
11.@property (strong, nonatomic) CLLocationManager *mgr;
12.
13.@end
14.
15.@implementation ViewController
16.
17.- (void)viewDidLoad {
18. [super viewDidLoad];
19.
20. // MARK: - 请求授权
21. // 1. 创建位置管理者对象
22. self.mgr = [CLLocationManager new];
23.
24. // 2. 请求授权
25. if ([self.mgr respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
26. [self.mgr requestWhenInUseAuthorization];
27. }
28.
29. // MARK: - 设置mapView属性
30.// self.mapView.userTrackingMode = MKUserTrackingModeFollow;
31. self.mapView.delegate = self;
32.}
33.
34.- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
35. // MARK: - 大头针一
36. MyAnnotationModel *model1 = [MyAnnotationModel new];
37. model1.coordinate = CLLocationCoordinate2DMake(40, 116);
38. model1.title = @"帝都";
39. model1.subtitle = @"充满魔力的城市";
40. model1.icon = @"苍老师";
41. [self.mapView addAnnotation:model1];
42.
43. // MARK: - 大头针二
44. MyAnnotationModel *model2 = [MyAnnotationModel new];
45. model2.coordinate = CLLocationCoordinate2DMake(23, 108);
46. model2.title = @"东莞";
47. model2.subtitle = @"充满美丽的城市";
48. model2.icon = @"自拍照";
49. [self.mapView addAnnotation:model2];
50.}
51.
52./**
53. 当往mapView中添加数据模型时, 便会来到此代理方法中返回大头针视图
54. 通常在该方法中自定义大头针视图, 该方法返回nil默认大头针视图类型由系统处理
55.
56. @param mapView 地图
57. @param annotation 大头针模型
58. @return 大头针视图
59. */
60.- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
61. // 1. 如果是"蓝色光圈", 则由系统决定
62. if ([annotation isKindOfClass:[MKUserLocation class]]) {
63. return nil;
64. }
65.
66. // 2. 创建大头针视图
67. MyAnnotationView *annotationView = [MyAnnotationView annotationViewWithMapView:mapView];
68.
69. // 3. 返回大头针视图
70. return annotationView;
71.}
72.
73.@end
?说明-1
:自定义大头针视图,点击大头针时,除了显示标题、子标题外;可以通过设置MKAnnotationView的leftCalloutAccessoryView、rightCalloutAccessoryView属性,可以在标题的左侧显示辅助视图。注意:当我们自定义大头针视图时,MKAnnotationView的canShowCallout属性默认为:NO;该属性值为NO时,左辅助视图不显示,所以,如果我们想实现自定义大头针视图显示左、右辅助视图时,必须设置canShowCallout属性的值为YES,否则,标题、子标题、左右辅助视图都将不会显示。
?说明-2
:MKAnnotationView在iOS9.0新增detailCalloutAccessoryView属性,该属性用以展示详细信息,一旦设置该属性之后,子标题将不再显示。
?说明-3
:封装创建自定义大头针视图,在外界提供一个创建自定义大头针视图的类方法即可。
?说明-4
:封装大头针view与封装cell的过程几乎一模一样,唯一一个地方不一样的是封装大头针view可以不用给大头针view传递数据模型;直接在外界使用大头针视图,在自定义大头针view的内部系统会自动调用模型的set方法;给大头针view设置数据,如果重写模型的set方法,一定要调用super;否则,程序将直接崩溃;在重写的模型set方法中我们可以将一些大头针view的通用设置封装进去(例如:给大头针设置图片),快速创建大头针view的方法只需要传入mapView即可。
iOS核心笔记—MapKit框架-基础