1.概念
mapView
2.逻辑结构:
逻辑结构
1.设置用户定位模式
@property (nonatomic) MKUserTrackingMode userTrackingMode;
MKUserTrackingMode 枚举: MKUserTrackingModeNone 不定位 MKUserTrackingModeFollow 定位 MKUserTrackingModeFollowWithHeading 定位并且显示方向
2.设置地图类型
@property (nonatomic) MKMapType mapType;
MKMapType 枚举: MKMapTypeStandard :普通地图(左图) MKMapTypeSatellite :卫星云图 (中图) MKMapTypeHybrid :普通地图覆盖于卫星云图之上(右图)
MKMapType 剩下两种MKMapTypeSatelliteFlyover和MKMapTypeHybridFlyover在中国区无法使用
剩下两种
3.定位的用户坐标
@property (nonatomic, readonly) MKUserLocation *userLocation;
4.当前界面地图的中心坐标
@property (nonatomic) CLLocationCoordinate2D centerCoordinate;
例子:使用当前地图界面的中心点回归到用户的坐标(只能中心点回归,范围回归需要设置region属性)
self.mapView.centerCoordinate = self.mapView.userLocation.location.coordinate;
5.设置代理
@property (nonatomic, weak, nullable) id <MKMapViewDelegate> delegate;
6.设置范围
@property (nonatomic) MKCoordinateRegion region;
MKCoordinateRegion 区域结构体包含 CLLocationCoordinate2D 经纬度( latitude 纬度, longitude 经度) MKCoordinateSpan 范围跨度 ,1度= 111千米( latitudeDelta 纬度跨度 , longitudeDelta 经度跨度) 两个结构体,每个结构体都是一个double值,所以region需要四个double
Span系统默认值为 MKCoordinateSpanMake(0.021256, 0.016093)
7.显示交通情况
@property (nonatomic) BOOL showsTraffic
显示交通状况
8.显示比例尺
@property (nonatomic) BOOL showsScale;

9.显示指南针(iOS9 默认YES,屏幕旋转手势之后出现,如果点击会校正方向)
@property (nonatomic) BOOL showsCompass;
指南针
1.以动画的方式设置区域,用于地图中心定位到用户所在位置
- (void)setRegion:(MKCoordinateRegion)region animated:(BOOL)animated;
2.在地图上添加一个大头针
- (void)addAnnotation:(id <MKAnnotation>)annotation;
3.将指定view上的point点转换成地图上的经纬度坐标,一般在touchesBegan中调用
- (CLLocationCoordinate2D)convertPoint:(CGPoint)point toCoordinateFromView:(nullable UIView *)view;
4.从缓存池中查找指定ID的自定义大头针模型
- (nullable MKAnnotationView *)dequeueReusableAnnotationViewWithIdentifier:(NSString *)identifier;
1.完成用户位置更新的时候会调用此方法,参数 MKUserLocation:用户定位位置的大头针模型
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation;
2.当地图的显示区域发生改变的时候调用
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated;
3.当添加大头针模型的时候调用此方法, 在大头针视图添加到地图之前调用,可用于自定义大头针(类似于cell创建方式),参数 annotation 为插到地图上的大头针模型,也包括系统的 如果返回nil,代表用户没有自定义需求,样式由系统处理。
- (nullable MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation;
注意:也包括系统定位用的大头针模型MKUserLocation !如果不想将其自定义要进行类型筛选判断
if ([annotation isKindOfClass:[MKUserLocation class]]) { return nil; }
4.在添加大头针图像出现之前调用,可以设置大头针的掉落效果 参数 views 大头针掉落后的图像,将大头针的y值设置为0(顶部),再动画回到原来的位置可实现 注意:不要将系统定位的大头针设置了动画效果
- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray<MKAnnotationView *> *)views;
重要属性,可以获取地图上的经纬度
@property (readonly, nonatomic, nullable) CLLocation *location; @property (readonly, nonatomic, getter=isUpdating) BOOL updating; @property (readonly, nonatomic, nullable) CLHeading *heading; @property (nonatomic, copy, nullable) NSString *title; @property (nonatomic, copy, nullable) NSString *subtitle;
例子
//拖一个mapView控件,一定要导入框架 @property (weak, nonatomic) IBOutlet MKMapView *mapView; //1. 显示用户位置,创建位置管理器请求授权 self.locationManager = [CLLocationManager new]; if ([self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) { [self.locationManager requestWhenInUseAuthorization]; } //2. 设置显示用户位置 用户跟踪模式 self.mapView.userTrackingMode = MKUserTrackingModeFollow; //3. 设置代理 获取数据 self.mapView.delegate = self; //代理方法,完成用户位置更新的时候会调用 - (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{ //1. 创建地理编码对象 CLGeocoder *geocoder = [CLGeocoder new]; //2. 调用方法,反地理编码 [geocoder reverseGeocodeLocation:userLocation.location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) { //3. 防错输出 if (placemarks.count == 0 || error) { return; } //3.1 获取地标对象 CLPlacemark *pm = placemarks.firstObject; // 大头针模型,能设置大头针的显示位置及标题子标题 userLocation.title = pm.administrativeArea; //3.3 设置子标题 详细地址 userLocation.subtitle = pm.name; }]; }
设置以用户位置为中心点 在mapView上创建一个按钮,点击按钮执行下面代码
//1. 获取用户定位的中心点经纬度 CLLocationCoordinate2D center = self.mapView.userLocation.location.coordinate; //2. 显示跨度 1度 ~111千米 MKCoordinateSpan span = MKCoordinateSpanMake(0.021256, 0.016093); //3. 动画设置地图的范围和中心点 [self.mapView setRegion: MKCoordinateRegionMake(center, span) animated:YES];
- (IBAction)zoomDaClick:(id)sender { CGFloat latitude = self.mapView.region.span.latitudeDelta * 0.5; //放大 * 2 CGFloat longitude = self.mapView.region.span.longitudeDelta * 0.5;//放大 * 2 //2. 设置 region,范围, 带动画 [self.mapView setRegion: MKCoordinateRegionMake(self.mapView.region.center, MKCoordinateSpanMake(latitude, longitude)) animated:YES]; //设置最大跨度 // if (latitude > 140 || longitude > 140) { // return; // } }
1、自定义系统类型大头针 (MKPinAnnotationView),使用的MKAnnotation大头针模型,只能改变大头针颜色,标题、子标题等属性 2、完全自定义大头针模型:创建一个模型类继承于NSObject,遵守协议 <MKAnnotation>,.h 选择设置以下属性,注意去掉readonly,其它属性如image可自定义
(1)经纬度,必须设置的属性
@property (nonatomic) CLLocationCoordinate2D coordinate;
(2)标题、子标题
@property (nonatomic, copy, nullable) NSString *title; @property (nonatomic, copy, nullable) NSString *subtitle;
(3)重新设置坐标
- (void)setCoordinate:(CLLocationCoordinate2D)newCoordinate;
1.MKAnnotationView :默认image属性没有赋值,可以完全自定义 (1)设置大头针可以被点击,用于显示附属视图、标题、子标题等,自定义时默认为NO,想要大头针被点击注意开启
@property (nonatomic) BOOL canShowCallout;
(2)设置左右边的附属视图
@property (strong, nonatomic, nullable) UIView *leftCalloutAccessoryView; @property (strong, nonatomic, nullable) UIView *rightCalloutAccessoryView;
效果:
左右边的附属视图
(3)iOS 9新增,自定义详情/子标题,原来的子标题文字没了,变成了自定义控件
@property (nonatomic, strong, nullable) UIView *detailCalloutAccessoryView
效果:
自定义子标题
2.MKPinAnnotationView: image属性已被设置(圆帽形状),只能更改颜色
(1)设置大头针颜色
@property (nonatomic) MKPinAnnotationColor pinColor;
MKPinAnnotationColor 颜色枚举: MKPinAnnotationColorRed MKPinAnnotationColorGreen MKPinAnnotationColorPurple
@property (strong, null_resettable) UIColor *pinTintColor( 9_0);
(2)是否开启动画掉落,默认为NO
@property (nonatomic) BOOL animatesDrop;
系统自定义大头针
完全自定义大头针
#pragma mark - 自定义一个MyAnnotation大头针模型类继承于NSObject,写上 coordinate、title、subtitle、icon(完全自定义用)等属性 #pragma mark - 点击插自定义大头针,给大头针模型设置值,之前在viewDisLoad中已申请授权定位 - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ // 获取点击的点 CGPoint point = [[touches anyObject] locationInView:self.mapView]; // point点换成地图上的经纬度的点 CLLocationCoordinate2D coordinate = [self.mapView convertPoint:point toCoordinateFromView:self.mapView]; // 创建一个自定义大头针对象 MyAnnotation *annotion = [MyAnnotation new]; // 大头针的位置就是点击的位置 annotion.coordinate = coordinate; // 此处可以利用反地理编码来获取该坐标的地址详情 annotion.title = @"优衣库"; annotion.subtitle = @"三里屯"; // annotion.icon = @"苍老师图片"; 完全自定义时设置自定义大头针的图片 // 将大头针添加到mapView上 [self.mapView addAnnotation:annotion]; } #pragma mark - 自定义系统样式大头针(与下面二选一),不同颜色的大头针方法(利用 MKPinAnnotationView) // 设置自定义大头针的显示样式,大头针视图添加到地图之前调用,类似于cell的创建方式 - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{ //判断是否是系统定位用的大头针 if ([annotation isKindOfClass:[MKUserLocation class]]) { return nil; } static NSString *ID = @"annoView"; //缓存池查找、创建一个MKPinAnnotationView类型的大头针 MKPinAnnotationView *annoView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:ID]; if (annoView == nil) { annoView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:ID]; // 设置颜色 annoView.pinColor = MKPinAnnotationColorRed; // 设置动画掉落 annoView.animatesDrop = YES; } return annoView; } #pragma mark - 完全自定义样式大头针(与上面二选一),不同图片的大头针方法(利用 MKAnnotationView),也可以直接调用封装好的自定义大头针view,且不必给大头针view设置大头针模型,系统会自动调用view的set方法进行设置 - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{ //判断是否是系统定位用的大头针 if ([annotation isKindOfClass:[MKUserLocation class]]) { return nil; } static NSString *ID = @"annoView"; //缓存池查找、创建一个完全自定义的大头针view MKAnnotationView *annoView = [mapView dequeueReusableAnnotationViewWithIdentifier:ID]; if (annoView == nil) { annoView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:ID]; // 使大头针可以被点击,可以查看附属视图 annoView.canShowCallout = YES; // 设置左边的附属视图 annoView.leftCalloutAccessoryView = [UISwitch new]; } // 获取大头针模型,封装后就不用设置模型了 MyAnnotation *anno = (MyAnnotation *)annotation; // 给大头针view设置模型数据(图像) annoView.image = [UIImage imageNamed:anno.icon]; return annoView; } #pragma mark - 实现大头针掉落动画效果 //代理方法在添加大头针图像出现之前调用,参数views 为放置的大头针 - (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray<MKAnnotationView *> *)views{ for (MKAnnotationView *annoView in views) { // 不要将系统定位的大头针设置了动画效果 if ([annoView.annotation isKindOfClass:[MKUserLocation class]]) { return; } // 记录要放置的大头针坐标的位置 CGRect startFrame = annoView.frame; // 位置的 Y 改为0,用来掉落 annoView.frame = CGRectMake(startFrame.origin.x, 0, startFrame.size.width, startFrame.size.height); // 执行动画掉落 [UIView animateWithDuration:0.25 animations:^{ annoView.frame = startFrame; }]; } }
1.创建一个类方法,参数有mapview,用于缓存池查找
+ (instancetype)annotationViewWithMapView:(MKMapView *)mapView;
2.实现
+ (instancetype)annotationViewWithMapView:(MKMapView *)mapView{ static NSString *ID = @"annoView"; MyAnnotationView *annoView = (MyAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:ID]; if (annoView == nil) { annoView = [[MyAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:ID]; annoView.canShowCallout = YES; annoView.leftCalloutAccessoryView = [UISwitch new]; } return annoView; } #pragma mark 系统会自动调用大头针view的 set 方法,一旦重写必须调用父类方法,不然会没有数据 - (void)setAnnotation:(MyAnnotation *)annotation{ //1. 调用 super 设置模型 [super setAnnotation:annotation]; //2. 设置图像 self.image = [UIImage imageNamed:annotation.icon]; }
步骤: 1、创建地理编码对象,调用正地理编码方法,获取 CLPlacemark 地标对象 2、构造方法用上面参数创建一个 MKPlacemark 对象 3、构造方法用上面参数创建一个 MKMapItem 对象,作为终点位置
MKMapItem 就是地图上的一个点
+ (BOOL)openMapsWithItems:(NSArray<MKMapItem *> *)mapItems launchOptions:(nullable NSDictionary<NSString *, id> *)launchOptions;
参数:
mapItems:要导航到的点 launchOptions:导航参数,字典,KEY值如下(注意整型的包装): 1、设置导航模式 MKLaunchOptionsDirectionsModeKe 枚举: MKLaunchOptionsDirectionsModeDriving 开车 MKLaunchOptionsDirectionsModeWalking 走路 MKLaunchOptionsDirectionsModeTransit 公交 2、设置地图类型 MKLaunchOptionsMapTypeKey 枚举: MKMapTypeStandard :标准模式 MKMapTypeSatellite :卫星模式 MKMapTypeHybrid :混合模式 3、是否显示交通状况,BOOL值 MKLaunchOptionsShowsTrafficKey 4、中心点坐标,CLLocationCoordinate2D类型 MKLaunchOptionsMapCenterKey 5、地图显示跨度,MKCoordinateSpan 类型 MKLaunchOptionsMapSpanKey 6、3D地图效果,MKMapCamera类型,iOS7及以后可用 MKLaunchOptionsCameraKey
- (IBAction)navigateClick:(id)sender { //1. 创建CLGeocoder对象 CLGeocoder *geocoder = [CLGeocoder new]; //2. 调用地理编码方法 [geocoder geocodeAddressString:self.destinationTF.text completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) { //3 防错处理 if (placemarks.count == 0 || error) { return; } //4. 获取地标对象 暂取最后一个 CLPlacemark *pm = placemarks.lastObject; //5. 创建MKPlacemark对象 MKPlacemark *mkpm = [[MKPlacemark alloc] initWithPlacemark:pm]; //6. 创建一个MKMapItem MKMapItem *destinationItem = [[MKMapItem alloc] initWithPlacemark:mkpm]; //7. 调用open类方法, 打开导航 NSDictionary *options = @{MKLaunchOptionsDirectionsModeKey : MKLaunchOptionsDirectionsModeDriving, MKLaunchOptionsMapTypeKey : @(MKMapTypeHybrid), MKLaunchOptionsShowsTrafficKey : @(YES)}; [MKMapItem openMapsWithItems:@[destinationItem] launchOptions:options]; }]; }
步骤:(就是各种转换,步骤多的看着就恶心,可以直接看下面代码) 1、创建地理编码对象,调用正地理编码方法,获取 CLPlacemark 地标对象 2、构造方法用上面参数创建一个 MKPlacemark 对象 3、构造方法用上面参数创建两个个 MKMapItem 对象,作为起点和终点位置 4、创建方向请求对象( MKDirectionsRequest ),分别设置起点和终点( source、 destination) 5、创建方向对象( MKDirections ),构造方法利用上面的请求对象 6、用方向对象调用计算两点之间的路线方法,回调获取 MKDirectionsResponse 类型响应 7、从响应对象中获取一组路线对象( MKRoute)路线对象,有些属性天朝用不了,如暴风雪路线 8、遍历该组路线对象,取出每个折线( polyline属性 MKPolyline类型)分别渲染到mapView上(通过mapView的 addOverlay:方法) 9、在mapView代理方法中创建地图渲染物 (1)创建折线渲染物对象( MKPolylineRenderer ),构造方法利用代理的 overlay 参数 (2)设置线条颜色(必须设置,否则不显示 fillColor 或 strokeColor ) (3)返回渲染对象
地图画线
#pragma mark 导航按钮点击 - (IBAction)navigateClick:(id)sender { // 回收键盘 [self.view endEditing:YES]; //1. 创建CLGeocoder对象 CLGeocoder *geocoder = [CLGeocoder new]; //2. 调用地理编码方法 [geocoder geocodeAddressString:self.destinationTF.text completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) { //3 防错处理 if (placemarks.count == 0 || error) { return; } //4. 获取地表对象 暂取最后一个 CLPlacemark *pm = placemarks.lastObject; //5. 创建MKPlacemark对象 MKPlacemark *mkpm = [[MKPlacemark alloc] initWithPlacemark:pm]; //6.1 创建一个终点MKMapItem MKMapItem *destinationItem = [[MKMapItem alloc] initWithPlacemark:mkpm]; //6.2 创建一个起点MKMapItem(当前位置) MKMapItem *souceItem = [MKMapItem mapItemForCurrentLocation]; //7. 创建一个方向请求对象,分别设置起点和终点 MKDirectionsRequest *request = [MKDirectionsRequest new]; //7.1 设置终点 request.destination = destinationItem; //7.2 设置起点 request.source = souceItem; //8. 创建方向对象,利用请求对象 MKDirections *direction = [[MKDirections alloc] initWithRequest:request]; //9. 调用请求对象的 计算路径方法 [direction calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse * _Nullable response, NSError * _Nullable error) { //10.1 防错处理 if (response.routes.count == 0 || error) { NSLog(@"没有找到对应的路线"); return ; } //10.2 从返回的response中获取一组 MKRoute 路线对象 for (MKRoute *route in response.routes) { //11. 从路线对象中获取折线对象 MKPolyline *polyline = route.polyline; //12. 将折线对象通过渲染方式添加到地图上,注意在渲染的代理方法中为折线设置颜色 [self.mapView addOverlay:polyline]; } }]; }]; } #pragma mark - mapView的代理方法,当给地图添加了遮盖物的时候就会用此方法,设置一个渲染物对象添加到地图上 - (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay{ //1. 创建一个折线渲染物对象(MKOverlayRenderer的子类) MKPolylineRenderer *polyline = [[MKPolylineRenderer alloc] initWithOverlay:overlay]; //2. 设置线条颜色,必须设置,否则看不见 polyline.fillColor = [UIColor redColor]; //polyline.strokeColor = [UIColor blueColor]; //3. 设置线条宽度 polyline.lineWidth = 10; return polyline; }
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
我来说两句