跟踪显示用户的位置
设置MKMapView的userTrackingMode属性可以跟踪显示用户的当前位置
MKUserTrackingModeNone
:不跟踪用户的位置
MKUserTrackingModeFollow
:跟踪并在地图上显示用户的当前位置
MKUserTrackingModeFollowWithHeading
:跟踪并在地图上显示用户的当前位置,地图会跟随用户的前进方向进行旋转
下图是跟踪效果
蓝色发光圆点就是用户的当前位置
蓝色发光原点,专业术语叫做“大头针”
地图的类型
可以通过设置MKMapView的mapType 设置地图类型
MKMapTypeStandard
:普通地图(左图)
MKMapTypeSatellite
:卫星云图 (中图)
MKMapTypeHybrid
:混合模式(普通地图覆盖于卫星云图之上
)
MKMapTypeSatelliteFlyover: 3D立体卫星 (iOS9.0)
MKMapTypeHybridFlyover: 3D立体混合 (iOS9.0)
设置地图的其他属性
操作项:
是否可缩放 zoomEnabled
是否可滚动 scrollEnabled
是否可旋转 rotateEnabled
显示项:
是否显示指南针 showsCompass (iOS9.0)
是否显示比例尺 showsScale (iOS9.0)
是否显示交通 showsTraffic (iOS9.0)
是否显示建筑 showsBuildings
使用注意
设置对应的属性时,注意该属性是从哪个系统版本开始引入的,做好不同系统版本的适配
追踪用户的位置
设置MKMapView的userTrackingMode属性可以跟踪显示用户的当前位置
MKUserTrackingModeNone
:不跟踪用户的位置
MKUserTrackingModeFollow
:跟踪并在地图上显示用户的当前位置
MKUserTrackingModeFollowWithHeading
:跟踪并在地图上显示用户的当前位置,地图会跟随用户的前进方向进行旋转
下图是跟踪效果
蓝色发光圆点就是用户的当前位置
蓝色发光圆点,专业术语叫做“大头针”
注意:iOS8.0之后,追踪用户位置需要用户进行定位授权
备注:
iOS8.0-,地图不会自动滚动到用户所在位置
iOS8.0+,地图会自动放大到合适比例,并显示出用户位置
MKMapView的代理
MKMapView可以设置一个代理对象,用来监听地图的相关行为
常见的代理方法有
- (void)mapView:(MKMapView*)mapView
didUpdateUserLocation:(MKUserLocation *)userLocation;
调用非常频繁,不断监测用户的当前位置
每次调用,都会把用户的最新位置(userLocation参数)传进来
- (void)mapView:(MKMapView*)mapView
regionWillChangeAnimated:(BOOL)animated;
地图的显示区域即将发生改变的时候调用
- (void)mapView:(MKMapView*)mapView
regionDidChangeAnimated:(BOOL)animated;
地图的显示区域已经发生改变的时候调用
MKUserLocation
MKUserLocation其实是个大头针模型,包括以下属性
@property (nonatomic, copy) NSString*title;
显示在大头针上的标题
@property (nonatomic, copy) NSString*subtitle;
显示在大头针上的子标题
@property (readonly, nonatomic) CLLocation*location;
地理位置信息(大头针钉在什么地方?)
设置地图的显示
通过MKMapView的下列方法,可以设置地图显示的位置和区域
设置地图的中心点位置
@property (nonatomic) CLLocationCoordinate2DcenterCoordinate;
- (void)setCenterCoordinate:(CLLocationCoordinate2D)coordinate animated:(BOOL)animated;
设置地图的显示区域
@property (nonatomic) MKCoordinateRegionregion;
- (void)setRegion:(MKCoordinateRegion)region animated:(BOOL)animated;
MKCoordinateRegion
MKCoordinateRegion是一个用来表示区域的结构体,定义如下
typedef struct{
CLLocationCoordinate2Dcenter; 区域的中心点位置
MKCoordinateSpanspan;
区域的跨度
} MKCoordinateRegion;
MKCoordinateSpan的定义
typedef struct{
CLLocationDegrees
latitudeDelta; 纬度跨度
CLLocationDegrees
longitudeDelta; 经度跨度
}
MKCoordinateSpan;
MKUserLocation
MKUserLocation其实是个大头针模型,包括以下属性
@property (nonatomic, copy) NSString*title;
显示在大头针上的标题
@property (nonatomic, copy) NSString*subtitle;
显示在大头针上的子标题
@property (readonly, nonatomic) CLLocation*location;
地理位置信息(大头针钉在什么地方?)
大头针的基本操作
添加一个大头针
- (void)addAnnotation:(id<MKAnnotation>)annotation;
添加多个大头针
- (void)addAnnotations:(NSArray*)annotations;
移除一个大头针
- (void)removeAnnotation:(id<MKAnnotation>)annotation;
移除多个大头针
- (void)removeAnnotations:(NSArray*)annotations;
(id<MKAnnotation>)annotation参数是什么东西?
大头针模型对象:用来封装大头针的数据,比如大头针的位置、标题、子标题等数据
大头针模型
新建一个大头针模型类
import <MapKit/MapKit.h>
@interface
MJTuangouAnnotation : NSObject <MKAnnotation>
/** 坐标位置 */
@property(nonatomic, assign) CLLocationCoordinate2Dcoordinate;
/** 标题 */
@property(nonatomic, copy) NSString*title;
/** 子标题 */
@property(nonatomic, copy) NSString*subtitle;
@end
添加大头针
MJTuangouAnnotation*anno = [[MJTuangouAnnotation
alloc] init];
anno.title = @"传智播客iOS学院";
anno.subtitle = @"全部课程15折,会员20折,老学员30折";
anno.coordinate = CLLocationCoordinate2DMake(40, 116);
[self.mapView addAnnotation:anno];
自定义大头针
如何自定义大头针
设置MKMapView的代理
实现下面的代理方法,返回大头针控件
- (MKAnnotationView
*)mapView:(MKMapView *)mapView
viewForAnnotation:(id <MKAnnotation>)annotation;
根据传进来的(id <MKAnnotation>)annotation参数创建并返回对应的大头针控件
代理方法的使用注意
如果返回nil,显示出来的大头针就采取系统的默认样式
标识用户位置的蓝色发光圆点,它也是一个大头针,当显示这个大头针时,也会调用代理方法
因此,需要在代理方法中分清楚(id<MKAnnotation>)annotation参数代表自定义的大头针还是蓝色发光圆点
自定义大头针
- (MKAnnotationView
*)mapView:(MKMapView *)mapView
viewForAnnotation:(id<MKAnnotation>)annotation
{
判断annotation的类型
if
(![annotation isKindOfClass:[MJTuangouAnnotation class]])
return nil;
创建MKAnnotationView
static NSString *ID = @"tuangou";
MKAnnotationView
*annoView = [mapView dequeueReusableAnnotationViewWithIdentifier:ID];
if (annoView
== nil) {
annoView = [[MKAnnotationView alloc]
initWithAnnotation:annotationreuseIdentifier:ID];
annoView.canShowCallout
= YES;
}
自定义大头针
传递模型数据
annoView.annotation
= annotation;
设置图片
MJTuangouAnnotation
*tuangouAnnotation = annotation;
annoView.image
= [UIImage imageNamed:tuangouAnnotation.icon];
return
annoView;
}
MKAnnotationView
地图上的大头针控件是MKAnnotationView
MKAnnotationView的属性
@property (nonatomic, strong) id<MKAnnotation> annotation;
大头针模型
@property (nonatomic, strong) UIImage*image;
显示的图片
@property (nonatomic) BOOLcanShowCallout;
是否显示标注
@property (nonatomic) CGPointcalloutOffset;
标注的偏移量
@property (strong, nonatomic) UIView
*rightCalloutAccessoryView;
标注右边显示什么控件
@property (strong, nonatomic) UIView
*leftCalloutAccessoryView;
标注左边显示什么控件
MKPinAnnotationView
MKPinAnnotationView是MKAnnotationView的子类
MKPinAnnotationView比MKAnnotationView多了2个属性
@property (nonatomic) MKPinAnnotationColorpinColor;
大头针颜色
@property (nonatomic) BOOLanimatesDrop;
大头针第一次显示时是否从天而降
MKMapItem调用系统APP进行导航
主要方法
[MKMapItem openMapsWithItems:items launchOptions:md];
示例代码
根据两个地标对象进行调用系统导航
- (void)beginNavWithBeginPlacemark:(CLPlacemark
*)beginPlacemark andEndPlacemark:(CLPlacemark *)endPlacemark
{
创建起点:根据
CLPlacemark 地标对象创建MKPlacemark 地标对象
MKPlacemark *itemP1 = [[MKPlacemark alloc]
initWithPlacemark:beginPlacemark];
MKMapItem *item1 = [[MKMapItem alloc]
initWithPlacemark:itemP1];
创建终点:根据
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:@[item1, item2]
launchOptions:launchDic];
}
MKMapCamera地图街景
主要方法
self.mapView.camera = camera;
示例代码
创建视角中心坐标
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;
MKMapSnapshotter地图截图
主要方法
[snapshotter startWithCompletionHandler:^(MKMapSnapshot
- _Nullable snapshot, NSError * _Nullable error) { }];
示例代码
截图附加选项
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];
}
}];
MKDirections获取导航路线信息
主要方法
[directions calculateDirectionsWithCompletionHandler:
^(MKDirectionsResponse * _Nullable response,
NSError * _Nullable error) {
}];
绘制路线,添加覆盖层等
主要方法
注意:这里不像添加大头针那样,只要我们添加了大头针模型,默认就会在地图上添加系统的大头针视图
添加覆盖层,需要我们实现对应的代理方法,在代理方法中返回对应的覆盖层
[self.mapView addOverlay:overlay];
调用了以上方法后,会调用以下代理方法获取对应的渲染涂层
-(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
MapKit框架的使用
一. 地图的基本使用
- 设置地图显示类型
地图的样式可以手动设置, 在iOS9.0之前有3种, iOS9.0之后增加了2种
1.设置方式
self.mapView.mapType = MKMapTypeStandard;
2.枚举类型
对应含义
MKMapTypeStandard
标准地图
MKMapTypeSatellite
卫星地图
MKMapTypeHybrid
混合模式(标准+卫星)
MKMapTypeSatelliteFlyover
3D立体卫星(iOS9.0)
MKMapTypeHybridFlyover
3D立体混合(iOS9.0)
- 设置地图控制项
地图的旋转, 缩放, 移动等等操作行为都可以开启或者关闭
设置方式
self.customMapView.zoomEnabled = YES; 是否缩放
self.customMapView.scrollEnabled = YES; 是否滚动
self.customMapView.rotateEnabled = YES; 是否旋转
self.customMapView.pitchEnabled = NO; 是否显示3DVIEW
- 设置地图显示项
地图上的指南针, 比例尺, 建筑物, POI点都可以控制是否显示
设置方式
self.customMapView.showsCompass = YES; 是否显示指南针
self.customMapView.showsScale = YES; 是否显示比例尺
self.customMapView.showsTraffic = YES; 是否显示交通
self.customMapView.showsBuildings = YES; 是否显示建筑物
- 显示用户位置
可以设置显示用户当前所在位置, 以一个蓝点的形式呈现在地图上
设置方式
方案1:(BOOL值)
self.customMapView.showsUserLocation =YES;
效果:
会在地图上显示一个蓝点, 标识用户所在位置; 但地图不会缩放, 而且当用户位置移动时, 地图不会跟随用户位置移动而移动
方案2:(追踪方向模式)
self.customMapView.userTrackingMode =
MKUserTrackingModeFollowWithHeading;
效果:
会在地图上显示一个蓝点, 标识用户所在位置; 而且地图缩放到合适比例,显示用户位置, 当用户位置移动时, 地图会跟随用户位置移动而移动; 但是有时候失效;
注意事项: 如果要显示用户位置, 在iOS8.0之后, 需要主动请求用户授权
测试环境
加载地图数据需要联网
XCode版本根据测试选择不同版本(iOS9.0 只能使用XCode7.0版本)
iOS系统版本根据测试选择不同版本(例如地图类型, 在iOS9.0之后才有新增)
常见问题总结
地图加载不显示?
检查网络是否通畅
- 地图放的太大都是格子, 禁止浏览
正常, 为了安全等原因, 不会看的太详细
- 地图运行起来APP占用内存非常大
正常, 地图加载了很多资源
- 用户位置不显示
首先, 检查代码, 是否有设置显示用户位置,是否有进行请求位置授权
其次, 查看模拟器是否有位置信息
第三, 重置模拟器, 模拟器又发神经了.
二. 地图的中级使用
- 查看当前用户位置信息
设置地图代理
实现代理方法
-(void)mapView:(MKMapView *)mapView
didUpdateUserLocation:(MKUserLocation *)userLocation
{
NSLog(@"%@", userLocation);
}
- 调整地图显示中心
确定地图中心经纬度坐标
CLLocationCoordinate2D
center = CLLocationCoordinate2DMake(21.123, 121.345);
设置地图中心为给定的经纬度坐标
[mapView
setCenterCoordinate:center animated:YES];
- 调整地图显示区域
获取合适的区域跨度
实现当地图区域发生改变时调用的代理代理方法, 并调整地图区域到合适比例, 并在对应的方法中, 获取对应的跨度信息
代码如下:
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
NSLog(@"%f---%f",
mapView.region.span.latitudeDelta, mapView.region.span.longitudeDelta);
}
创建一个区域(包含区域中心, 和区域跨度)
CLLocationCoordinate2D center = CLLocationCoordinate2DMake(21.123, 121.345);
MKCoordinateSpan span = MKCoordinateSpanMake(0.1, 0.1);
MKCoordinateRegion region = MKCoordinateRegionMake(center, span);
设置地图显示区域
[self.mapView setRegion:region animated:YES];
概念解释
MKCoordinateSpan
跨度解释:
latitudeDelta:纬度跨度,因为南北纬各90.0度,所以此值的范围是(0.0---180.0);此值表示,整个地图视图宽度,显示多大跨度;
longitudeDelta:经度跨度,因为东西经各180.0度,所以此值范围是(0.0---360.0):此值表示,整个地图视图高度,显示多大跨度;
注意:地图视图显示,不会更改地图的比例,会以地图视图高度或宽度较小的那个为基准,按比例调整
- MKUserLocation 大头针数据模型详解
MKUserLocation
: 被称作“大头针(数据)模型”;
其实喊什么都行,本质就是一个数据模型,只不过此模型遵循了大头针要遵循的协议(MKAnnotation)
重要属性:
location
: 用户当前所在位置信息(CLLocation对象)
title
: 大头针标注要显示的标题(NSString对象)
subtitle
: 大头针标注要显示的子标题(NSString对象)
测试环境
加载地图数据需要联网
XCode版本不限
iOS系统版本不限
常见问题总结
地图上的蓝点为啥不显示?
第一: 确定代码是否有误(例如, 是否显示了用户位置)
第二: 确定模拟器是否设置位置
第三: 看下位置在哪, 是不是不在当前地图显示区域
- 地图跨度设置之后,
最终显示的跨度和设置数值不一致?
因为地球的不是正方形的, 随着用户的位置移动, 会自动修正地图跨度, 保持地图不变形;
三. 地图高级-大头针基本使用
- 理论支撑(必须掌握)
按照MVC的原则
- 在地图上操作大头针,实际上是控制大头针数据模型
添加大头针就是添加大头针数据模型
删除大头针就是删除大头针数据模型
- 在地图上添加大头针视图
自定义大头针数据模型
创建继承自NSObject的数据模型XMGAnnotation,
遵循大头针数据模型必须遵循的协议(MKAnnotation)注意将协议@property 中的readonly 去掉;
创建大头针数据模型, 并初始化参数
XMGAnnotation *annotation = [[XMGAnnotation alloc] init];
annotation.coordinate = coordinate;
annotation.title = @"小码哥";
annotation.subtitle = @"小码哥分部";
调用地图的添加大头针数据模型方法
[self.customMapView addAnnotation:annotation];
- 移除大头针(所有大头针)
NSArray *annotations = self.customMapView.annotations;
[self.customMapView removeAnnotations:annotations];
- 场景模拟
场景描述:
鼠标点击在地图哪个位置, 就在对应的位置添加一个大头针, 并在标注弹框中显示对应的城市和街道;
实现步骤
- 获取触摸点在地图上对应的坐标
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self.customMapView];
- 将坐标转换成为经纬度
CLLocationCoordinate2D center = [self.customMapView
convertPoint:touchPoint toCoordinateFromView:self.customMapView];
- 根据经纬度创建大头针数据模型, 并添加在地图上
XMGAnnotation *annotation = [[XMGAnnotation alloc] init];
annotation.coordinate = coordinate;
annotation.title = @"小码哥";
annotation.subtitle = @"小码哥分部";
[self.customMapView addAnnotation:annotation];
- 利用反地理编码,
获取该点对应的城市和街道名称, 然后修改大头针数据模型
注意: 设置弹框数据时, 对应的大头针数据模型应有对应的占位数据(这样对应的UI才会生成,后面才能重新修改数据)
测试环境
加载地图数据需要联网
XCode版本不限
iOS系统版本不限
常见问题总结
反地理编码无法获取对应的数据
第一: 检查是否有联网
第二: 检查代码是否有误
第三: 有时存在某些位置没有反地理编码结果, 换个点尝试, 如果都没有, 排除此原因
- 大头针协议遵循,属性?
@property , 其实就是生成了get,
和 set 方法;
所以, 遵循这个协议, 等同于实现该属性的get, set方法
四. 地图高级-大头针的自定义
- 理论支撑
按照MVC的原则
每当添加一个大头针数据模型时, 地图就会调用对应的代理方法, 查找对应的大头针视图,显示在地图上;
如果该方法没有实现, 或者返回nil, 那么就会使用系统默认的大头针视图
- 模拟系统默认的大头针实现方案
实现当添加大头针数据模型时,地图回调的代理方法
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(XMGAnnotation *)annotation
{
}
实现须知
大头针系统对应的视图是 MKPinAnnotationView,它继承自MKAnnotationView
地图上的大头针视图,和tableview上的cell一样,都使用“循环利用”的机制
实现代码
static NSString *pinID = @"pinID";
MKPinAnnotationView *pinView = (MKPinAnnotationView *)[mapView
dequeueReusableAnnotationViewWithIdentifier:pinID];
if (!pinView) {
pinView = [[MKPinAnnotationView alloc] initWithAnnotation:nil
reuseIdentifier:pinID];
}
pinView.annotation = annotation;
弹出标注
pinView.canShowCallout = YES;
修改大头针颜色
pinView.pinColor = MKPinAnnotationColorPurple;
设置大头针从天而降
pinView.animatesDrop = YES;
设置大头针可以被拖拽(父类中的属性)
pinView.draggable =YES;
return pinView;
- 自定义大头针
实现当添加大头针数据模型时,地图回调的代理方法
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(XMGAnnotation *)annotation
{
}
实现须知
如果想要自定义大头针, 必须使用MKAnnotationView 或者 自定义的子类
但是不能直接使用系统默认的大头针, 会无效
实现代码
自定义大头针
static NSString *pinID = @"pinID";
MKAnnotationView *customPinView = [mapView dequeueReusableAnnotationViewWithIdentifier:pinID];
if (!customPinView) {
customPinView = [[MKAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:pinID];
}
设置大头针图片
customPinView.image = [UIImage imageNamed:@"category_3"];
设置大头针可以弹出标注
customPinView.canShowCallout = YES;
设置标注左侧视图
UIImageView *leftIV = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 40, 40)];
leftIV.image = [UIImage imageNamed:@"huba.jpeg"];
customPinView.leftCalloutAccessoryView = leftIV;
设置标注右侧视图
UIImageView *rightIV = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 40, 40)];
rightIV.image = [UIImage imageNamed:@"eason.jpg"];
customPinView.rightCalloutAccessoryView = rightIV;
设置标注详情视图(iOS9.0)
customPinView.detailCalloutAccessoryView = [[UISwitch alloc] init];
return customPinView;
- 代理方法补充
选中一个大头针时调用
-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
NSLog(@"选中%@", [view.annotation title]);
}
取消选中大头针时调用
-(void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view
{
NSLog(@"取消选中%@", [view.annotation title]);
}
测试环境
加载地图数据需要联网
XCode版本不限
iOS系统版本不限
常见问题总结
代码运行在低版本的XCode上, 编译失败
第一: 语法错误; XCode7.0 对于OC语法优化了一些, 需要手动调整
第二: iOS9.0的SDK, 在XCode7.0之前的版本没有对应的API
五. 利用系统App导航
导航的三种实现方案
可以将需要导航的位置丢给系统的地图APP进行导航
发送网络请求到公司服务器获取导航数据, 然后自己手动绘制导航
利用三方SDK实现导航(百度)
- 直接将起点和终点, 传递给系统地图, 利用系统APP, 进行导航
利用"反推法", 记住关键代码即可
代码如下:
根据两个地标对象进行调用系统导航
- (void)beginNavWithBeginPlacemark:(CLPlacemark *)beginPlacemark andEndPlacemark:(CLPlacemark *)endPlacemark
{
创建起点:根据CLPlacemark 地标对象创建MKPlacemark 地标对象
MKPlacemark *itemP1 = [[MKPlacemark alloc] initWithPlacemark:beginPlacemark];
MKMapItem *item1 = [[MKMapItem alloc] initWithPlacemark:itemP1];
创建终点:根据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:@[item1, item2] launchOptions:launchDic];
}
注意: CLPlacemark地标对象没法直接手动创建, 只能通过(反)地理编码获取
- 补充
3D视图
补充1:类似于地图街景,增强用户体验
CLLocationCoordinate2D center = CLLocationCoordinate2DMake(23.132931, 113.375924);
MKMapCamera *camera = [MKMapCamera cameraLookingAtCenterCoordinate:center fromEyeCoordinate:CLLocationCoordinate2DMake(center.latitude, center.longitude + 0.001) eyeAltitude:1];
self.mapView.camera = camera;
地图截图
截图附加选项
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];
}
}];
测试环境
加载地图数据需要联网
XCode版本不限
iOS系统版本不限
常见问题总结
需要注意地标对象不能手动创建, 因为里面的属性是readonly; 只能通过(反)地理编码获取
六. 获取导航路线信息
- 实现须知
获取导航路线, 需要想苹果服务器发送网络请求
记住关键对象MKDirections
2.代码实现
根据两个地标,向苹果服务器请求对应的行走路线信息
- (void)directionsWithBeginPlackmark:(CLPlacemark
*)beginP andEndPlacemark:(CLPlacemark *)endP
{
创建请求
MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init];
设置开始地标
MKPlacemark *beginMP = [[MKPlacemark alloc] initWithPlacemark:beginP];
request.source = [[MKMapItem alloc] initWithPlacemark:beginMP];
设置结束地标
MKPlacemark *endMP = [[MKPlacemark alloc] initWithPlacemark:endP];
request.destination = [[MKMapItem alloc] initWithPlacemark:endMP];
根据请求,获取实际路线信息
MKDirections *directions = [[MKDirections alloc] initWithRequest:request];
[directions
calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *
_Nullable response,
NSError * _Nullableerror) {
[response.routes enumerateObjectsUsingBlock:^(MKRoute * _Nonnull obj, NSUInteger
idx,
BOOL * _Nonnull
stop) {
NSLog(@"%@--", obj.name);
[obj.steps enumerateObjectsUsingBlock:^(MKRouteStep * _Nonnull
obj, NSUInteger idx, BOOL *_Nonnull stop) {
NSLog(@"%@",
obj.instructions);
}];
}];
}];
}
- 导航路线对象详解
/**
MKDirectionsResponse对象解析
source :开始位置
destination :结束位置
routes : 路线信息 (MKRoute对象)
MKRoute对象解析
name : 路的名称
advisoryNotices :
注意警告信息
distance :
路线长度(实际物理距离,单位是m)
polyline :
路线对应的在地图上的几何线路(由很多点组成,可绘制在地图上)
steps :
多个行走步骤组成的数组(例如“前方路口左转”,“保持直行”等等,
MKRouteStep 对象)
MKRouteStep对象解析
instructions :
步骤说明(例如“前方路口左转”,“保持直行”等等)
transportType :
通过方式(驾车,步行等)
polyline :
路线对应的在地图上的几何线路(由很多点组成,可绘制在地图上)
注意:
MKRoute是一整条长路;MKRouteStep是这条长路中的每一截;
*/
测试环境
请求路线数据需要联网
XCode版本不限
iOS系统版本不限
常见问题总结
类太多, 记不住咋办?
此功能不常用, 只需要知道有这一个功能. 如果到时用到, 直接回过头来找代码;
七. 绘制导航路线
- 理论支持
1.路线也是一个覆盖层
在地图上操作覆盖层,其实操作的是覆盖层的数据模型
添加覆盖层:在地图上添加覆盖层数据模型 删除覆盖层:在地图上移除覆盖层数据模型
- 添加导航路线到地图
1.获取几何路线的数据模型(id
)overlay
2.地图添加覆盖层(几何路线也是一个覆盖层), 直接添加覆盖层数据模型
[self.mapView addOverlay:overlay];
3.设置地图代理, 代理遵循协议
MKMapViewDelegate
4.实现地图添加覆盖层数据模型时, 回调的代理方法; 通过此方法, 返回对应的渲染图层
- (MKOverlayRenderer
*)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{
创建折线渲染对象
if ([overlay isKindOfClass:[MKPolyline class]])
{
MKPolylineRenderer *lineRenderer = [[MKPolylineRenderer alloc]
initWithOverlay:overlay];
设置线宽
lineRenderer.lineWidth = 6;
设置线颜色
lineRenderer.strokeColor = [UIColor redColor];
return lineRenderer;
}
}
- 练习: 添加圆形覆盖层到地图
1.创建圆形区域覆盖层的数据模型
MKCircle *circle =
[MKCircle circleWithCenterCoordinate:self.mapView.centerCoordinate
radius:1000000];
2.添加覆盖层数据模型
[self.mapView addOverlay:circle];
3.实现代理方法
-(MKOverlayRenderer
*)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{
创建圆形区域渲染对象
if ([overlay isKindOfClass:[MKCircle class]])
{
MKCircleRenderer *circleRender = [[MKCircleRenderer alloc]
initWithOverlay:overlay];
circleRender.fillColor = [UIColor cyanColor];
circleRender.alpha = 0.6;
return circleRender;
}
return nil;
}
测试环境
地图加载需要联网
XCode版本不限
iOS系统版本不限
常见问题总结
东西太多, 记不住?
只需要记得一个思想, 按照MVC的原则, 我们操作覆盖层, 就是操作覆盖层数据模型; 然后地图, 会调用其对应的代理方法, 获取对应的覆盖层渲染层;
类记不住没关系, 主要记住大致思路就可以.
八. 集成百度地图
集成原因
有些功能, 系统自带的高德地图无法实现, 例如POI检索等等
一般实现导航功能,
会集成百度地图的比较多;
集成步骤
下载对应的SDK
按照集成文档一步一步实现
开发经验
不要把所有的功能全部都写在控制器当中, 最好封装成一个单独的工具类
如果集成过程中出现问题, 先查看官方文档
测试环境
需要联网
XCode版本不限
iOS系统版本不限
- 常见问题总结
按照开发文档一步一步做, 一般没有什么问题; 注意集成细节就行.