地图的样式能够手动设置, 在iOS9.0以前有3种, iOS9.0以后增长了2种git
设置方式数组
self.mapView.mapType = MKMapTypeStandard;
枚举类型 | 对应含义 |
---|---|
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点均可以控制是否显示网络
设置方式app
self.customMapView.showsCompass = YES; // 是否显示指南针 self.customMapView.showsScale = YES; // 是否显示比例尺 self.customMapView.showsTraffic = YES; // 是否显示交通 self.customMapView.showsBuildings = YES; // 是否显示建筑物 self.mapView.showsPointsOfInterest = YES; // 兴趣点 self.mapView.showsBuildings = YES; // 建筑物
能够设置显示用户当前所在位置, 以一个蓝点的形式呈如今地图上框架
设置方式测试
方案1: self.customMapView.showsUserLocation = YES; 效果: 会在地图上显示一个蓝点, 标识用户所在位置; 但地图不会缩放, 并且当用户位置移动时, 地图不会跟随用户位置移动而移动 方案2: self.customMapView.userTrackingMode = MKUserTrackingModeFollowWithHeading; 效果: 会在地图上显示一个蓝点, 标识用户所在位置; 并且地图缩放到合适比例,显示用户位置, 当用户位置移动时, 地图会跟随用户位置移动而移动; 可是有时候失效;
注意事项: 若是要显示用户位置, 在iOS8.0以后, 须要主动请求用户受权优化
1. 加载地图数据须要联网 2. XCode版本根据测试选择不一样版本(iOS9.0 只能使用 XCode7.0版本) 3. iOS系统版本根据测试选择不一样版本(例如地图类型, 在iOS9.0以后才有新增)
1. 地图加载不显示? 检查网络是否通畅 2. 地图放的太大都是格子, 禁止浏览 正常, 为了安全等缘由, 不会看的太详细 3. 地图运行起来APP占用内存很是大 正常, 地图加载了不少资源 4. 用户位置不显示 首先, 检查代码, 是否有设置显示用户位置,是否有进行请求位置受权 其次, 查看模拟器是否有位置信息 第三, 重置模拟器, 模拟器又发神经了.
实现代理方法ui
-(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 : 被称做“大头针(数据)模型”; 其实叫什么都行,本质就是一个数据模型,只不过此模型遵循了大头针要遵循的协议(MKAnnotation) 重要属性: location : 用户当前所在位置信息(CLLocation对象) title : 大头针标注要显示的标题(NSString对象) subtitle : 大头针标注要显示的子标题(NSString对象)
1. 加载地图数据须要联网 2. XCode版本不限 3. iOS系统版本不限
1. 地图上的蓝点为啥不显示? 第一: 肯定代码是否有误(例如, 是否显示了用户位置) 第二: 肯定模拟器是否设置位置 第三: 看下位置在哪, 是否是不在当前地图显示区域 2. 地图跨度设置以后, 最终显示的跨度和设置数值不一致? 由于地球的不是正方形的, 随着用户的位置移动, 会自动修正地图跨度, 保持地图不变形;
按照MVC的原则 * 在地图上操做大头针,其实是控制大头针数据模型 1. 添加大头针就是添加大头针数据模型 2. 删除大头针就是删除大头针数据模型
自定义大头针数据模型
1) 建立继承自NSObject的数据模型CJAnnotation, 遵循大头针数据模型必须遵循的协议(MKAnnotation) 2) 注意将协议@property 中的readonly 去掉;
建立大头针数据模型, 并初始化参数
CJAnnotation *annotation = [[CJAnnotation alloc] init]; annotation.coordinate = coordinate; annotation.title = @"吖了个J"; annotation.subtitle = @"大屌哈哈";
调用地图的添加大头针数据模型方法
[self.customMapView addAnnotation:annotation];
NSArray *annotations = self.customMapView.annotations; [self.customMapView removeAnnotations:annotations];
场景描述:
鼠标点击在地图哪一个位置, 就在对应的位置添加一个大头针, 并在标注弹框中显示对应的城市和街道;
实现步骤
1. 获取触摸点在地图上对应的坐标 UITouch *touch = [touches anyObject]; CGPoint touchPoint = [touch locationInView:self.customMapView]; 2. 将坐标转换成为经纬度 CLLocationCoordinate2D center = [self.customMapView convertPoint:touchPoint toCoordinateFromView:self.customMapView]; 3. 根据经纬度建立大头针数据模型, 并添加在地图上 CJAnnotation *annotation = [[CJAnnotation alloc] init]; annotation.coordinate = coordinate; annotation.title = @"吖了个J"; annotation.subtitle = @"大屌哈哈"; [self.customMapView addAnnotation:annotation]; 4. 利用反地理编码, 获取该点对应的城市和街道名称, 而后修改大头针数据模型 注意: 设置弹框数据时, 对应的大头针数据模型应有对应的占位数据(这样对应的UI才会生成,后面才能从新修改数据)
1. 加载地图数据须要联网 2. XCode版本不限 3. iOS系统版本不限
1. 反地理编码没法获取对应的数据 第一: 检查是否有联网 第二: 检查代码是否有误 第三: 有时存在某些位置没有反地理编码结果, 换个点尝试, 若是都没有, 排除此缘由
按照MVC的原则 1. 每当添加一个大头针数据模型时, 地图就会调用对应的代理方法, 查找对应的大头针视图,显示在地图上; 2. 若是该方法没有实现, 或者返回nil, 那么就会使用系统默认的大头针视图
实现当添加大头针数据模型时,地图回调的代理方法
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation { }
实现须知
1. 大头针系统对应的视图是 MKPinAnnotationView,它继承自 MKAnnotationView 2. 地图上的大头针视图,和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:(id<MKAnnotation>)annotation { }
实现须知
1. 若是想要自定义大头针, 必须使用 MKAnnotationView 或者 自定义的子类 2. 可是不能直接使用系统默认的大头针, 会无效
实现代码
// 自定义大头针 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]); }
1. 加载地图数据须要联网 2. XCode版本不限 3. iOS系统版本不限
1. 代码运行在低版本的XCode上, 编译失败 第一: 语法错误; XCode7.0 对于OC语法优化了一些, 须要手动调整 第二: iOS9.0的SDK, 在XCode7.0以前的版本没有对应的API
1. 能够将须要导航的位置丢给系统的地图APP进行导航 2. 发送网络请求到公司服务器获取导航数据, 而后本身手动绘制导航 3. 利用三方SDK实现导航(百度)
代码以下:
// 根据两个地标对象进行调用系统导航 - (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视图
相似于地图街景,加强用户体验 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/xxxx/Desktop/snap.png" atomically:YES]; } }];
1. 加载地图数据须要联网 2. XCode版本不限 3. iOS系统版本不限
1. 须要注意地标对象不能手动建立, 由于里面的属性是readonly; 只能经过(反)地理编码获取
// 根据两个地标,向苹果服务器请求对应的行走路线信息 - (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) { [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是这条长路中的每一截; */
1. 请求路线数据须要联网 2. XCode版本不限 3. iOS系统版本不限
1. 类太多, 记不住咋办? 此功能不经常使用, 只须要知道有这一个功能. 若是到时用到, 直接回过头来找代码;
地图添加覆盖层(几何路线也是一个覆盖层), 直接添加覆盖层数据模型
[self.mapView addOverlay:overlay];
实现地图添加覆盖层数据模型时, 回调的代理方法; 经过此方法, 返回对应的渲染图层
- (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; } }
建立圆形区域覆盖层的数据模型
MKCircle *circle = [MKCircle circleWithCenterCoordinate:self.mapView.centerCoordinate radius:1000000];
添加覆盖层数据模型
[self.mapView addOverlay:circle];
实现代理方法
-(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; }
1. 地图加载须要联网 2. XCode版本不限 3. iOS系统版本不限
1. 东西太多, 记不住? 只须要记得一个思想, 按照MVC的原则, 咱们操做覆盖层, 就是操做覆盖层数据模型; 而后地图, 会调用其对应的代理方法, 获取对应的覆盖层渲染层; 类记不住不要紧, 主要记住大体思路就能够.