'' // 1.设置地图显示类型
'' /**
'' MKMapTypeStandard = 0, // 标准
'' MKMapTypeSatellite, // 卫星
'' MKMapTypeHybrid, // 混合(标准+卫星)
'' MKMapTypeSatelliteFlyover NS_ENUM_AVAILABLE(10_11, 9_0), // 3D立体卫星
'' MKMapTypeHybridFlyover NS_ENUM_AVAILABLE(10_11, 9_0), // 3D立体混合
'' */
'' self.customMapView.mapType = MKMapTypeStandard;
- 设置地图的其他属性(操作项)
* 注意:设置对应的属性时,注意该属性是从哪个系统版本开始引入的,做好不同系统版本的适配 *
'' // 是否可以缩放
'' self.customMapView.zoomEnabled = NO;
'' // 是否可以滚动
'' self.customMapView.scrollEnabled = NO;
'' // 是否可以旋转
'' self.customMapView.rotateEnabled = NO;
'' // 是否显示3D
'' self.customMapView.pitchEnabled = NO;
- 设置地图其它属性(显示项)
'' // 是否显示指南针
'' self.customMapView.showsCompass = YES;
'' // 是否显示比例尺
'' self.customMapView.showsScale = YES;
'' // 是否显示交通
'' self.customMapView.showsTraffic = YES;
'' // 是否显示建筑物
'' self.customMapView.showsBuildings = YES;
'' -(CLLocationManager *)locationM
'' {
'' if (!_locationM) {
'' _locationM = [[CLLocationManager alloc] init];
'' if ([_locationM respondsToSelector:@selector(requestAlwaysAuthorization)]) {
'' [_locationM requestAlwaysAuthorization];
'' }
'' }
'' return _locationM;
'' }
2. 设置地图的用户追踪模式
*(注意:设置此属性会使用到用户的位置隐私,所以需要请求用户授权,否则没有效果)*
'' /**
'' MKUserTrackingModeNone = 0, // 不跟随
'' MKUserTrackingModeFollow, // 跟随用户位置
'' MKUserTrackingModeFollowWithHeading, // 跟随用户位置,并跟随用户方向
'' */
'' [self locationM];
'' self.customMapView.userTrackingMode = MKUserTrackingModeFollowWithHeading;
''-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
'' {
'' /**
'' MKUserLocation : 被称作“大头针模型”,其实喊什么都行,本质就是一个数据模型,只不过此模型遵循了大头针要遵循的协议(MKAnnotation)
'' location: 用户当前所在位置信息(CLLocation对象)
'' title: 大头针标注要显示的标题(NSString对象)
'' subtitle: 大头针标注要显示的子标题(NSString对象)
'' */
'' // 根据用户当前位置的经纬度,设置地图显示中心
'' /**
'' 存在弊端:地图显示比例过大,无法调整
'' 解决方案:直接使用对应的调整地图“显示区域”的API
'' */
'' // [mapView setCenterCoordinate:userLocation.coordinate animated:YES];
'' /**
'' MKCoordinateSpan 跨度解释:
'' latitudeDelta:纬度跨度,因为南北纬各90度,所以此值的范围是(0---180);此值表示,整个地图视图宽度,显示多大跨度
'' longitudeDelta:经度跨度,因为东西经各180度,所以此值范围是(0---360):此值表示,整个地图视图高度,显示多大跨度
'' 注意:地图视图显示,不会更改地图的比例,会以地图视图高度或宽度较小的那个为基准,按比例调整
'' */
'' // MKCoordinateSpan span = MKCoordinateSpanMake(0.1, 0.1);
'' // MKCoordinateRegion region = MKCoordinateRegionMake(userLocation.coordinate, span);
'' // [mapView setRegion:region animated:YES];
'' }
''
'' // 当地图区域(跨度)改变时调用
'' -(void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
'' {
'' NSLog(@"%f---%f", mapView.region.span.latitudeDelta, mapView.region.span.longitudeDelta);
'' }
** 必须理解: 在地图上操作大头针,实际上是控制大头针数据模型
* 添加大头针就是添加大头针数据模型 *
* 删除大头针就是删除大头针数据模型 *
- 添加一个/多个大头针
1. 自定义大头针模型(需要遵循MKAnnotation协议)
''#import
''
'' @interface XMGAnnotation : NSObject
''
'' @property (nonatomic, assign) CLLocationCoordinate2D coordinate;
'' @property (nonatomic, copy, nullable) NSString *title;
'' @property (nonatomic, copy, nullable) NSString *subtitle;
''
'' @end
2. 创建自定义大头针模型,并添加到地图上
'' -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
'' {
'' // 如果我们仅仅添加大头针数据模型,地图上会自动添加系统默认的大头针视图
'' XMGAnnotation *annotation = [[XMGAnnotation alloc] init];
'' // annotation.coordinate = self.mapView.centerCoordinate;
'' // 1. 获取当前点的位置
'' UITouch *touch = [touches anyObject];
'' CGPoint point = [touch locationInView:self.mapView];
'' // 把点转换成对应的经纬度
'' CLLocationCoordinate2D coordinate = [self.mapView convertPoint:point toCoordinateFromView:self.mapView];
'' // TODO:使用反地理编码,获取对应大头针的所在的位置信息,通过标注显示出来
'' annotation.coordinate = coordinate;
'' annotation.title = @"小码哥";
'' annotation.subtitle = @"小��哥分部";
''
'' // 添加单个大头针
'' [self.mapView addAnnotation:annotation];
'' // 添加多个大头针
'' // [self.mapView addAnnotations:@[]];
'' }
- 移除一个/多个大头针
'' [self.mapView removeAnnotations:self.mapView.annotations];
* 添加大头针数据模型时, 其实地图会调用代理方法查找对应的大头针视图, 如果没有找到, 就会使用系统默认的大头针视图 *
1. 模拟系统大头针实现方案,并对系统大头针进行部分自定义
''- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation
'' {
'' if ([annotation isKindOfClass:[MKUserLocation class]]) {
'' return nil;
'' }
'' // 如果此方法返回nil, 就会使用系统自带的大头针视图
'' // 模拟下,返回nil,系统的解决方案
'' static NSString *pinId = @"pinID";
'' MKPinAnnotationView *pinView = ( MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:pinId];
'' if (pinView == nil) {
'' pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:pinId];
'' }
'' pinView.annotation = annotation;
'' // 是否显示标注
'' pinView.canShowCallout = YES;
'' // 设置大头针颜色
'' pinView.pinColor = MKPinAnnotationColorPurple;
'' // 设置大头针是否有下落动画
'' pinView.animatesDrop = YES;
'' return pinView;
'' }
*(弹出标注, 修改大头针颜色, 设置大头针从天而降, 设置大头针可以被拖拽)*
'' - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation
'' {
'' if ([annotation isKindOfClass:[MKUserLocation class]]) {
'' return nil;
'' }
'' /** 自定义大头针-------*/
'' static NSString *pinId = @"pinID";
'' MKAnnotationView *annoView = [mapView dequeueReusableAnnotationViewWithIdentifier:pinId];
'' if (annoView == nil) {
'' annoView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:pinId];
'' }
'' annoView.annotation = annotation;
'' annoView.image = [UIImage imageNamed:@"category_5"];
'' annoView.canShowCallout = YES;
'' UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"huba.jpeg"]];
'' imageView.bounds = CGRectMake(0, 0, 44, 44);
'' annoView.leftCalloutAccessoryView = imageView;
'' imageView.userInteractionEnabled = YES;
'' UIImageView *imageView2 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"eason.jpg"]];
'' imageView2.bounds = CGRectMake(0, 0, 44, 44);
'' annoView.rightCalloutAccessoryView = imageView2;
'' annoView.detailCalloutAccessoryView = [UISwitch new];
'' annoView.draggable = YES;
'' return annoView;
'' }
* 大头针图标,大头针标注,左侧视图,右侧视图,详情视图,等;*
3. 选中,和取消选中大头针时的代理方法
''// 点击标注
'' - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
'' {
'' NSLog(@"点击标注");
'' }
'' // 选中大头针
'' - (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
'' {
'' NSLog(@"选中大头针");
'' }
'' // 取消选中大头针
'' -(void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view
'' {
'' NSLog(@"取消选中大头针");
'' }
''// 根据两个地标对象进行调用系统导航
'' - (void)beginNavWithBeginPlacemark:(CLPlacemark *)beginPlacemark andEndPlacemark:(CLPlacemark *)endPlacemark
'' {
''
'' // 根据 CLPlacemark 地标对象创建 MKPlacemark 地标对象
'' MKPlacemark *itemP1 = [[MKPlacemark alloc] initWithPlacemark:beginPlacemark];
'' MKMapItem *item1 = [[MKMapItem alloc] initWithPlacemark:itemP1];
''
''
'' 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];
''
'' }
''
'' /**
'' 补充1:类似于地图街景,增强用户体验
'' */
'' CLLocationCoordinate2D center = CLLocationCoordinate2DMake(23.132931, 113.375924);
'' MKMapCamera *camera = [MKMapCamera cameraLookingAtCenterCoordinate:center fromEyeCoordinate:CLLocationCoordinate2DMake(center.latitude + 0.001, center.longitude + 0.001) eyeAltitude:1];
'' self.mapView.camera = camera;
'' /**
'' 补充2:地图截图
'' */
'' // 截图附加选项
'' 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];
'' }
'' }];
''// 根据两个地标,向苹果服务器请求对应的行走路线信息
'' - (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 * _Nullable error) {
''
'' /**
'' MKDirectionsResponse对象解析
'' source :开始位置
'' destination :结束位置
'' routes : 路线信息 (MKRoute对象)
''
'' MKRoute对象解析
'' name : 路的名称
'' advisoryNotices : 注意警告信息
'' distance : 路线长度(实际物理距离,单位是m)
'' polyline : 路线对应的在地图上的几何线路(由很多点组成,可绘制在地图上)
'' steps : 多个行走步骤组成的数组(例如“前方路口左转”,“保持直行”等等, MKRouteStep 对象)
''
'' MKRouteStep对象解析
'' instructions : 步骤说明(例如“前方路口左转”,“保持直行”等等)
'' transportType : 通过方式(驾车,步行等)
'' polyline : 路线对应的在地图上的几何线路(由很多点组成,可绘制在地图上)
''
'' 注意:
'' MKRoute是一整条长路;MKRouteStep是这条长路中的每一截;
''
'' */
'' [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);
'' }];
'' }];
''
'' }];
''
'' }
''
* 路线也是一个覆盖层 *
* 理论指导:在地图上操作覆盖层,其实操作的是覆盖层的数据模型 *
* 添加覆盖层:在地图上添加覆盖层数据模型 *
* 删除覆盖层:在地图上移除覆盖层数据模型 *
1. 创建线路覆盖层模型,并添加到地图上
'' // 绘制线路
'' - (void)drawMapLine:(id )overlay
'' {
'' /**
'' 注意:这里不像添加大头针那样,只要我们添加了大头针模型,默认就会在地图上添加系统的大头针视图
'' 添加覆盖层,需要我们实现对应的代理方法,在代理方法中返回对应的覆盖层
'' */
'' [self.mapView addOverlay:overlay];
''
'' /** 补充测试:添加一个圆形覆盖层 */
'' // MKCircle *circle = [MKCircle circleWithCenterCoordinate:self.mapView.centerCoordinate radius:1000000];
'' // [self.mapView addOverlay:circle];
'' }
''
2. 利用地图的代理方法,返回对应的图层渲染
''-(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id)overlay{
''// 创建折线渲染对象
'' if ([overlay isKindOfClass:[MKPolyline class]]) {
'' MKPolylineRenderer *lineRenderer = [[MKPolylineRenderer alloc] initWithOverlay:overlay];
''// 设置线宽
'' lineRenderer.lineWidth = 6;
''// 设置线颜色
'' lineRenderer.strokeColor = [UIColor redColor];
'' return lineRenderer;
''}
''// 创建圆形区域渲染对象
''// if ([overlay isKindOfClass:[MKCircle class]]) {
''// MKCircleRenderer *circleRender = [[MKCircleRenderer alloc] initWithOverlay:overlay];
''// circleRender.fillColor = [UIColor cyanColor];
''// circleRender.alpha = 0.6;
''// return circleRender;
''// }
''return nil;
''
''}