1、MapKit框架简介:

✨了解:MapKit框架使用须知:①、MapKit框架中所有的数据类型的前缀都是MK;②、需要导入#import <MapKit/MapKit.h>头文件;③、MapKit框架中有一个非常重要的UI控件:MKMapView,专门用于地图显示,例如:大头针、路线、覆盖层展示等(着重界面展示)。


1-1、地图设置:
1-1-1、设置地图显示类型:

地图类型

MKMapTypeStandard普通地图
MKMapTypeSatellite卫星云图
MKMapTypeHybrid混合模式(普通地图覆盖于卫星云图之上 )
MKMapTypeSatelliteFlyover3D立体卫星(iOS9.0
MKMapTypeHybridFlyover3D立体混合(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是否显示用户的位置

1-2、使用注意:

2、大头针基本使用:


2-1、显示用户位置:
.#import "ViewController.h"
.#import <MapKit/MapKit.h>
.
.@interface ViewController () <MKMapViewDelegate>
./** 地图控件 */
.@property (weak, nonatomic) IBOutlet MKMapView *mapView;
./** 位置管理者对象 */
.@property (strong, nonatomic) CLLocationManager *mgr;
.
.@end
.
.@implementation ViewController
.
.- (void)viewDidLoad {
. [super viewDidLoad];
.
. // 1. 创建位置管理者对象
. self.mgr = [CLLocationManager new];
.
. // 2. 请求定位授权
. if ([self.mgr respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
. [self.mgr requestWhenInUseAuthorization];
. }
.
. // 3. 设置用户跟踪模式, 以便在mapView中显示用户的位置
.// self.mapView.userTrackingMode = MKUserTrackingModeFollow;
. self.mapView.userTrackingMode = MKUserTrackingModeFollowWithHeading;
.
. // 4. 设置mapView的代理, 监听mapView上用户的移动
. self.mapView.delegate = self;
.}
.
.#pragma mark - MKMapViewDelegate
.
./**
36. mapView中用户位置更新完毕调用
37. */
.- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{
. NSLog(@"%@", userLocation.location);
.}
.
.@end

显示用户位置模式

MKUserTrackingModeNone = 0默认模式, 不显示用户位置
MKUserTrackingModeFollow = 1显示用户位置, 无方向箭头; 常用于只需要显示用户位置
MKUserTrackingModeFollowWithHeading = 2显示用户位置, 并显示方向箭头; 常用于导航

MKUserLocation(模型)

updating判断用户位置是否已更新
location位置对象
heading设备朝向
title触摸大头针显示的标题
subtitle触摸大头针显示的子标题

2-2、模拟追踪显示用户位置:

.#import "ViewController.h"
.#import <MapKit/MapKit.h>
.
.@interface ViewController () <MKMapViewDelegate>
./** 地图控件 */
.@property (weak, nonatomic) IBOutlet MKMapView *mapView;
./** 位置管理者对象 */
.@property (strong, nonatomic) CLLocationManager *mgr;
.
.@end
.
.@implementation ViewController
.
.- (void)viewDidLoad {
. [super viewDidLoad];
.
. // 1. 创建位置管理者对象
. self.mgr = [CLLocationManager new];
.
. // 2. 请求定位授权
. if ([self.mgr respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
. [self.mgr requestWhenInUseAuthorization];
. }
.
. // 3. 设置用户跟踪模式, 以便在mapView中显示用户的位置
. self.mapView.userTrackingMode = MKUserTrackingModeFollowWithHeading;
.
. // 4. 设置mapView的代理, 监听mapView上用户的移动
. self.mapView.delegate = self;
.}
.
./**
33. 设置用户当前所在位置为mapView显示区域中心点坐标
34. mapView显示区域 : 当前展示在手机屏幕中的区域即为显示区域
35. */
.- (IBAction)backMapCenter:(UIButton *)sender {
. // MARK: - 方式一 : 设置mapView的centerCoordinate属性,
. // 只能改变mapView中心点坐标, 无法改变跨度
.// self.mapView.centerCoordinate = self.mapView.userLocation.location.coordinate;
. // 带动画的方式
. [self.mapView setCenterCoordinate:self.mapView.userLocation.location.coordinate animated:YES];
.
. // MARK: - 方式二 : 设置mapView的region属性
. // 能同时改变mapView的中心点位置、显示区域的跨度
. // 1. 创建显示区域中心点坐标
. CLLocationCoordinate2D center = self.mapView.userLocation.location.coordinate;
.
. // 2. 设置显示区域的跨度
. MKCoordinateSpan span = MKCoordinateSpanMake(0.01, 0.01);
.
. // 3. 动画设置用户位置为mapView中心点位置
. [self.mapView setRegion:MKCoordinateRegionMake(center, span) animated:YES];
.}
.
./**
56. mapView显示区域会调用该方法, 在该方法中能够获取mapView系统的跨度
57. */
.- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated{
. NSLog(@"latitudeDelta : %lf, longitudeDelta : %lf", mapView.region.span.latitudeDelta, mapView.region.span.longitudeDelta);
.}
.@end


2-3、缩放地图:

./**
2. 放大地图, 实质是减小跨度值
3. */
.- (IBAction)zoomInClick:(UIButton *)sender {
. // 1. 修改跨度
. CLLocationDegrees latitudeDelta = self.mapView.region.span.latitudeDelta * 0.5;
. CLLocationDegrees longitudeDelta = self.mapView.region.span.longitudeDelta * 0.5;
.
. // 2. 重置mapView的region
. self.mapView.region = MKCoordinateRegionMake(self.mapView.region.center, MKCoordinateSpanMake(latitudeDelta, longitudeDelta));
.}
.
./**
14. 缩小地图, 实质是增大跨度值
15. */
.- (IBAction)zoomOutClick:(UIButton *)sender {
. // 1. 修改跨度
. CLLocationDegrees latitudeDelta = self.mapView.region.span.latitudeDelta * ;
. CLLocationDegrees longitudeDelta = self.mapView.region.span.longitudeDelta * ;
.
. // 2. 重置mapView的region
. self.mapView.region = MKCoordinateRegionMake(self.mapView.region.center, MKCoordinateSpanMake(latitudeDelta, longitudeDelta));
.}


3、自定义大头针:

3-1、自定义大头针数据模型:

详细步骤

第一步导入MapKit框架
第二步自定义模型类继承自NSObject,遵守MKAnnotation协议
第三步拷贝协议中的所有属性, 并删除readonly
第四步创建自定义大头针数据模型对象
第五步自定义大头针数据模型对象添加到mapView中

自定义大头针数据模型

.#import <Foundation/Foundation.h>
.#import <MapKit/MapKit.h>
.
.@interface MyAnnotationModel : NSObject <MKAnnotation>
./** 大头针位置 */
.@property (nonatomic) CLLocationCoordinate2D coordinate;
./** 大头针标题 */
.@property (nonatomic, copy, nullable) NSString *title;
./** 大头针子标题 */
.@property (nonatomic, copy, nullable) NSString *subtitle;
.
.@end

使用自定义大头针数据模型

.#import "ViewController.h"
.#import <MapKit/MapKit.h>
.#import "MyAnnotationModel.h"
.
.@interface ViewController ()
./** 地图视图 */
.@property (weak, nonatomic) IBOutlet MKMapView *mapView;
.
.@end
.
.@implementation ViewController
.
.- (void)viewDidLoad {
. [super viewDidLoad];
.
. // 1. 创建大头针数据模型
. MyAnnotationModel *model = [MyAnnotationModel new];
.
. // 2. 设置大头针数据模型属性
. model.coordinate = CLLocationCoordinate2DMake(, );
. model.title = @"帝都";
. model.subtitle = @"充满魅力的城市";
.
. // 3. 添加到mapView
. [self.mapView addAnnotation:model];
.}
.
.- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
. // 1. 获取触摸点坐标
. CGPoint point = [[touches anyObject] locationInView:self.mapView];
.
. // 2. 将点转换为经纬度
. CLLocationCoordinate2D coordinate = [self.mapView convertPoint:point toCoordinateFromView:self.mapView];
.
. // 3. 创建自定义大头针数据模型
. MyAnnotationModel *model = [MyAnnotationModel new];
.
. // 4. 设置大头针数据模型相关属性
. model.coordinate = coordinate;
. model.title = @"圣安东尼奥";
. model.subtitle = @"诸葛维奇_马刺队";
.
. // 5. 添加到mapView
. [self.mapView addAnnotation:model];
.}
.
.@end

3-2、自定义大头针视图:

详细步骤

第一步创建大头针视图静态重用标识
第二步从缓存池中查找是否有可重用的大头针视图
第三步判断大头针视图是否创建成功,如果创建不成功,则手动创建大头针视图(通常使用MKAnnotationView的子类MKPinAnnotationView创建大头针视图)
第四步给大头针视图设置属性值(MKPinAnnotationView类才有相关属性)
第五步返回大头针视图

.#import "ViewController.h"
.#import <MapKit/MapKit.h>
.#import "MyAnnotationModel.h"
.
.@interface ViewController () <MKMapViewDelegate>
./** 地图视图 */
.@property (weak, nonatomic) IBOutlet MKMapView *mapView;
./** 位置管理者对象 */
.@property (strong, nonatomic) CLLocationManager *mgr;
.
.@end
.
.@implementation ViewController
.
.- (void)viewDidLoad {
. [super viewDidLoad];
.
. // MARK: - 定位授权
. // 1. 创建位置管理者对象
. self.mgr = [CLLocationManager new];
.
. // 2. 请求授权, 使用如下形式进行授权操作, 等价于已经做好版本适配操作
. // 因为, iOS8.0之前, 位置管理者对象没有requestWhenInUseAuthorization方法
. if ([self.mgr respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
. [self.mgr requestWhenInUseAuthorization];
. }
.
. // MARK: - 添加大头针
. // 1. 创建大头针数据模型
. MyAnnotationModel *model = [MyAnnotationModel new];
.
. // 2. 设置大头针数据模型属性
. model.coordinate = CLLocationCoordinate2DMake(, );
. model.title = @"帝都";
. model.subtitle = @"充满魅力的城市";
.
. // 3. 添加到mapView
. [self.mapView addAnnotation:model];
.
. // MARK: - 设置mapView相关属性
. self.mapView.userTrackingMode = MKUserTrackingModeFollow; // 显示用户位置
. self.mapView.delegate = self; // 设置代理
.}
.
.- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
. // 1. 获取触摸点坐标
. CGPoint point = [[touches anyObject] locationInView:self.mapView];
.
. // 2. 将点转换为经纬度
. CLLocationCoordinate2D coordinate = [self.mapView convertPoint:point toCoordinateFromView:self.mapView];
.
. // 3. 创建自定义大头针数据模型
. MyAnnotationModel *model = [MyAnnotationModel new];
.
. // 4. 设置大头针数据模型相关属性
. model.coordinate = coordinate;
. model.title = @"圣安东尼奥";
. model.subtitle = @"诸葛维奇_马刺队";
.
. // 5. 添加到mapView
. [self.mapView addAnnotation:model];
.}
.
./**
65. 当mapView添加"大头针数据模型"时, 便会来到该方法返回"大头针视图"
66. 没有实现该代理方法、或者返回为nil, 表示大头针视图类型由系统决定
67.
68. @param mapView 地图视图
69. @param annotation 大头针数据模型
70. @return 大头针视图
71. */
.- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
. // 0. 显示系统类型大头针视图
. if ([annotation isKindOfClass:[MKUserLocation class]]) {
. // 返回nil, 表示大头针视图类型由系统决定
. return nil;
. }
.
. // 1. 定义静态重用标识
. static NSString *ID = @"annotation";
.
. // 2. 从缓存池中查找可重用的大头针视图
. // MKAnnotationView : 该类型大头针视图默认image属性为nil, 不显示
. // MKPinAnnotationView : 为MKAnnotationView的子类, 默认为红色
.// MKAnnotationView *annot = [self.mapView dequeueReusableAnnotationViewWithIdentifier:ID];
. MKPinAnnotationView *pin = (MKPinAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:ID];
.
. // 3. 判断缓存池是否有可重用的大头针视图
. if (pin == nil) {
. pin = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:ID];
.
. // MARK: - 设置大头针视图属性
. // 1. 设置颜色
. // pinTintColor : iOS9.0设置大头针视图颜色属性
. // pinColor : iOS9.0之前设置大头针颜色属性
. pin.pinTintColor = [UIColor colorWithRed:((float)arc4random_uniform() / 255.0) green:((float)arc4random_uniform() / 255.0) blue:((float)arc4random_uniform() / 255.0) alpha:1.0];
.
. // 2. 设置动画掉落
.// pin.animatesDrop = YES;
. }
.
. // 4. 返回大头针视图
. return pin;
.}
.@end


4、模拟系统大头针掉落动画效果:


4-1、详细步骤:
第一步记录大头针在mapView中要显示的位置
第二步将大头针视图的frame设置到屏幕外
第三步在UIView动画中将大头针视图的frame还原至之前需要显示的位置。注意事项:所有操作必须是在大头针还未显示前的代理方法中执行,在给自定义大头针视图添加掉落动画效果时需要对显示用户位置的“蓝色光圈”大头针进行特殊处理;通过大头针视图对应的大头针数据模型的类型进行区分,避免“蓝色光圈”也带有掉落动画效果。记得要在返回大头针视图的代理方法中设置大头针的image属性

4-2、示例代码:
.#import "ViewController.h"
.#import "MyAnnotationModel.h"
.#import "MyAnnotationView.h"
.
.#import <MapKit/MapKit.h>
.
.@interface ViewController () <MKMapViewDelegate>
./** 地图视图 */
.@property (weak, nonatomic) IBOutlet MKMapView *mapView;
./** 位置管理者对象 */
.@property (strong, nonatomic) CLLocationManager *mgr;
.
.@end
.
.@implementation ViewController
.
.- (void)viewDidLoad {
. [super viewDidLoad];
.
. // MARK: - 请求授权
. // 1. 创建位置管理者对象
. self.mgr = [CLLocationManager new];
.
. // 2. 请求授权
. if ([self.mgr respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
. [self.mgr requestWhenInUseAuthorization];
. }
.
. // MARK: - 设置mapView属性
.// self.mapView.userTrackingMode = MKUserTrackingModeFollow;
. self.mapView.delegate = self;
.}
.
.- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
. // MARK: - 大头针一
. MyAnnotationModel *model1 = [MyAnnotationModel new];
. model1.coordinate = CLLocationCoordinate2DMake(, );
. model1.title = @"帝都";
. model1.subtitle = @"充满魔力的城市";
. model1.icon = @"苍老师";
. [self.mapView addAnnotation:model1];
.
. // MARK: - 大头针二
. MyAnnotationModel *model2 = [MyAnnotationModel new];
. model2.coordinate = CLLocationCoordinate2DMake(, );
. model2.title = @"东莞";
. model2.subtitle = @"充满美丽的城市";
. model2.icon = @"自拍照";
. [self.mapView addAnnotation:model2];
.}
.
.
.#pragma mark - <MKMapViewDelegate>
./**
55. 当往mapView中添加数据模型时, 便会来到此代理方法中返回大头针视图
56. 通常在该方法中自定义大头针视图, 该方法返回nil默认大头针视图类型由系统处理
57.
58. @param mapView 地图
59. @param annotation 大头针模型
60. @return 大头针视图
61. */
.- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
. // 1. 如果是"蓝色光圈", 则由系统决定
. if ([annotation isKindOfClass:[MKUserLocation class]]) {
. return nil;
. }
.
. // 2. 创建大头针视图
. MyAnnotationView *annotationView = [MyAnnotationView annotationViewWithMapView:mapView];
.
. // 3. 返回大头针视图
. return annotationView;
.}
.
./**
76. 大头针视图还未显示时会调用该方法
77.
78. @param mapView 地图
79. @param views 所有大头针视图
80. */
.- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray<MKAnnotationView *> *)views{
. // 如果没有大头针视图, 则直接返回
. if (views.count == ) {
. return ;
. }
.
. // 遍历大头针视图数组, 添加掉落动画
. for (MKAnnotationView *annotView in views) {
. // 1. 如果是"蓝色光圈", 则不需要添加动画
. if ([annotView.annotation isKindOfClass:[MKUserLocation class]]) {
. continue; // 记住: 此处是使用continue, 因为还需要进行下一次遍历操作
. }
.
. // 2. 记录大头针显示位置
. CGRect endFrame = annotView.frame;
.
. // 3. 改变大头针的frame
. annotView.frame = CGRectMake(annotView.frame.origin.x, -, annotView.bounds.size.width, annotView.bounds.size.height);
.
. // 4. 动画还原大头针至原定显示位置
. [UIView animateWithDuration:3.0 animations:^{
. annotView.frame = endFrame;
. }];
. }
.}
.
.@end

5、封装自定义大头针视图:

示例代码一:大头针视图内部实现

.#import "MyAnnotationView.h"
.#import "MyAnnotationModel.h"
.
.@implementation MyAnnotationView
.
.+ (instancetype)annotationViewWithMapView:(MKMapView *)mapView{
. // 1. 定义静态重用标识
. static NSString *ID = @"annotationView";
.
. // 2. 从缓存池中查找
. MyAnnotationView *annotationView = (MyAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:ID];
.
. // 3. 判断缓存池中是否有可重用的大头针视图
. if (annotationView == nil) {
. annotationView = [[MyAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:ID];
. }
.
. // 4. 返回大头针视图
. return annotationView;
.}
.
./**
23. 无论外界是否有使用到大头针的模型属性, 系统都会自动调用该方法
24. 重写该方法之后, 一定要调用super方法; 否则, 程序直接崩溃
25. */
.- (void)setAnnotation:(id<MKAnnotation>)annotation{
. [super setAnnotation:annotation];
.
. // 4.1. 设置大头针图片, 一旦自定义大头针视图, image默认为: nil
. MyAnnotationModel *model = annotation; // 强转
. self.image = [UIImage imageNamed:model.icon];
.
. // 4.2 显示标题/子标题, 自定义大头针视图默认为: NO, 将不显示标题/子标题/辅助视图
. self.canShowCallout = YES;
.
. // 4.3 左右辅助视图
. self.leftCalloutAccessoryView = [UISwitch new];
. self.rightCalloutAccessoryView = [UISwitch new];
.
. // 4.4 iOS9.0 新增属性: 标题下面可以设置详细视图, 设置该属性之后将会覆盖子标题
. self.detailCalloutAccessoryView = [UISwitch new];
.}
.
.@end

示例代码二:外界使用

.#import "ViewController.h"
.#import "MyAnnotationModel.h"
.#import "MyAnnotationView.h"
.
.#import <MapKit/MapKit.h>
.
.@interface ViewController () <MKMapViewDelegate>
./** 地图视图 */
.@property (weak, nonatomic) IBOutlet MKMapView *mapView;
./** 位置管理者对象 */
.@property (strong, nonatomic) CLLocationManager *mgr;
.
.@end
.
.@implementation ViewController
.
.- (void)viewDidLoad {
. [super viewDidLoad];
.
. // MARK: - 请求授权
. // 1. 创建位置管理者对象
. self.mgr = [CLLocationManager new];
.
. // 2. 请求授权
. if ([self.mgr respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
. [self.mgr requestWhenInUseAuthorization];
. }
.
. // MARK: - 设置mapView属性
.// self.mapView.userTrackingMode = MKUserTrackingModeFollow;
. self.mapView.delegate = self;
.}
.
.- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
. // MARK: - 大头针一
. MyAnnotationModel *model1 = [MyAnnotationModel new];
. model1.coordinate = CLLocationCoordinate2DMake(, );
. model1.title = @"帝都";
. model1.subtitle = @"充满魔力的城市";
. model1.icon = @"苍老师";
. [self.mapView addAnnotation:model1];
.
. // MARK: - 大头针二
. MyAnnotationModel *model2 = [MyAnnotationModel new];
. model2.coordinate = CLLocationCoordinate2DMake(, );
. model2.title = @"东莞";
. model2.subtitle = @"充满美丽的城市";
. model2.icon = @"自拍照";
. [self.mapView addAnnotation:model2];
.}
.
./**
53. 当往mapView中添加数据模型时, 便会来到此代理方法中返回大头针视图
54. 通常在该方法中自定义大头针视图, 该方法返回nil默认大头针视图类型由系统处理
55.
56. @param mapView 地图
57. @param annotation 大头针模型
58. @return 大头针视图
59. */
.- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
. // 1. 如果是"蓝色光圈", 则由系统决定
. if ([annotation isKindOfClass:[MKUserLocation class]]) {
. return nil;
. }
.
. // 2. 创建大头针视图
. MyAnnotationView *annotationView = [MyAnnotationView annotationViewWithMapView:mapView];
.
. // 3. 返回大头针视图
. return annotationView;
.}
.
.@end


04-30 11:24