目录
1. 地图
1.1 大头针(即标注)
1.2 Overlay覆盖物
1.3 MKMapViewDelegate
1.4 苹果原生地图App
2. 定位
2.1 地理编码与反编码
3. POI检索
4. 相关类
注意:
iOS8.0后 地图需要权限(info.plist中添加):
NSLocationAlwaysUsageDescription 始终需要
或者
NSLocationWhenInUseUsageDescription 仅在使用期间
CLLocationManager中相应两个请求权限的方法:
requestAlwaysAuthorization
requestWhenInUseAuthorization
模拟器默认没有地理位置,可使用调试栏中的箭头设置地理坐标
使用
0.导入MapKit框架
#import
#import
1. 地图
MKMapView
// :UIView
MKMapView *mapView=[MKMapView new];
[self.view addSubview:mapView];
// 地图类型
mapView.mapType=MKMapTypeStandard;
/**
MKMapTypeStandard :标准地图(常用)显示街道
MKMapTypeSatellite :卫星地图
MKMapTypeHybrid :混合地图(加载最慢,消耗资源)卫星地图上显示街道
MKMapTypeSatelliteFlyover NS_ENUM_AVAILABLE(10_11, 9_0),//立体卫星
MKMapTypeHybridFlyover NS_ENUM_AVAILABLE(10_11, 9_0),//立体混合
*/
用户位置
// 是否显示用户位置
[mapV setShowsUserLocation:true];
// 用户位置是否可见(readOnly)
BOOL isShowUser=mapV.userLocationVisible;
// 用户追踪类型
MKUserTrackingMode tankMode=mapV.userTrackingMode;
// 追踪类型(显示用户位置)
[mapV setUserTrackingMode: MKUserTrackingModeNone];
[mapV setUserTrackingMode: MKUserTrackingModeNone animated:true];
/**
MKUserTrackingModeNone : 不追踪;
MKUserTrackingModeFollow : 追踪用户位置;
MKUserTrackingModeFollowWithHeading : 追踪用户位置并且追踪用户前进方向;
*/
// 用户位置(readonly)
MKUserLocation *userLocation=mapView.userLocation;
/**
userLocation.location // location
userLocation.subtitle // 用户所在位置的Annotation的subTitle
userLocation.title // 用户所在位置的Annotation的title
userLocation.heading //
userLocation.isUpdating // 是否持续更新
*/
交互
// 是否允许缩放
[mapV setZoomEnabled:true];
// 是否允许滚动
[mapV setScrollEnabled:true];
// 是否允许旋转
[mapV setRotateEnabled:true];
// 是否支持3D地图
[mapV setPitchEnabled:true];
// 是否显示兴趣点
[mapV setShowsPointsOfInterest:true];
// 是否显示建筑物轮廓(尽在标准地图中有效)
[mapV setShowsBuildings:true];
// 是否显示罗盘
[mapV setShowsCompass:true];
// 是否显示缩放比例尺
[mapV setShowsScale:true];
// 是否显示交通拥堵状况
[mapV setShowsTraffic:true];
中心位置
// 设置地图的中心点
[mapV setCenterCoordinate:CLLocationCoordinate2DMake(39, 116)];
[mapV setCenterCoordinate:CLLocationCoordinate2DMake(39, 116) animated:true];
// 设置地图的显示范围(中心点经纬度,显示经纬度范围)(纬度39~41,经度116~118)
[mapV setRegion:MKCoordinateRegionMake(CLLocationCoordinate2DMake(39, 116), MKCoordinateSpanMake(2, 2))];
[mapV setRegion:MKCoordinateRegionMake(CLLocationCoordinate2DMake(39, 116), MKCoordinateSpanMake(2, 2)) animated:true];
/**
typedef struct {
CLLocationCoordinate2D center; // 地图中心的经纬度
MKCoordinateSpan span; // 地图显示的经纬度范围
} MKCoordinateRegion;
//
typedef struct {
CLLocationDegrees latitude; // 纬度,北纬为正
CLLocationDegrees longitude; // 经度,东经为正
} CLLocationCoordinate2D;
typedef struct {
CLLocationDegrees latitudeDelta; // 纬度范围(0~180) 超了会崩
CLLocationDegrees longitudeDelta; // 经度范围(0-360)
} MKCoordinateSpan;
*/
坐标转换
// 将 地理坐标点 转换为 代码坐标点
CGPoint point=[mapV convertCoordinate:CLLocationCoordinate2DMake(39, 116) toPointToView:[UIView new]];
// 将 代码坐标点 转换为 地理坐标点
CLLocationCoordinate2D location=[mapV convertPoint:CGPointMake(0, 100) toCoordinateFromView:[UIView new]];
// 将 地理坐标区域 转换为 代码坐标区域
CGRect rect=[mapV convertRegion:MKCoordinateRegionMake(CLLocationCoordinate2DMake(39, 116), MKCoordinateSpanMake(2, 2)) toRectToView:[UIView new]];
// 将 代码坐标区域 转换为 地理坐标区域
MKCoordinateRegion region=[mapV convertRect:CGRectMake(0, 0, 100, 200) toRegionFromView:[UIView new]];
1.1 大头针(即标注)
// 1. 添加大头针(可以自定义)
MKPointAnnotation *pointAn=[MKPointAnnotation new];
// 大头针位置
[pointAn setCoordinate:CLLocationCoordinate2DMake(39.1, 116.1)];
// 大头针下边标题
[pointAn setTitle:@"title"];
// 大头针下边副标题
[pointAn setSubtitle:@"subTitle"];
[mapV addAnnotation:pointAn];
// 2. 重绘大头针视图---不写时为默认视图
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation{
//
if(![annotation isKindOfClass:[大头针自定义类 class]]){
//
MKAnnotationView *annotationView=[mapView dequeueReusableAnnotationViewWithIdentifier:@"iden"];
if(!annotationView){
annotationView=[[MKAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:@"iden"];
// 设置可拖拽(默认:false)
annotationView.draggable=YES;
// 允许弹出气泡(点击后弹出,默认:false)
annotationView.canShowCallout=true;
// 气泡视图偏移量
annotationView.calloutOffset=CGPointMake(0, 1);
// 气泡视图右侧视图
aniView.rightCalloutAccessoryView=[UIView new];
// 气泡视图左侧视图
annotationView.leftCalloutAccessoryView=[[UIImageView alloc]initWithImage:[UIImage imageNamed:@"气泡视图左侧视图"]];
}
return annotationView;
}
return nil;
}
MKPointAnnotation大头针(即标注)
// 获取所有大头针(readOnly)
NSArray *annotationArr=mapView.annotations;
// 添加/移除大头针
[mapView addAnnotation:<#(nonnull id)#>];
[mapV addAnnotations:<#(nonnull NSArray> *)#>];
[mapView removeAnnotation:<#(nonnull id)#>];
[mapV removeAnnotations:<#(nonnull NSArray> *)#>];
// 注册大头针
[mapV registerClass:[Class class] forAnnotationViewWithReuseIdentifier:@"iden"];
// 获取指定区域内的大头针
NSSet> *rectAnnimation=[mapV annotationsInMapRect:MKMapRectMake(0, 0, 30, 30)];
// 获取大头针视图
MKAnnotationView *anView=[mapV viewForAnnotation:<#(nonnull id)#>];
// 获取大头针视图(复用)
MKAnnotationView *anView=[mapV dequeueReusableAnnotationViewWithIdentifier:@""];
MKAnnotationView *anView=[mapV dequeueReusableAnnotationViewWithIdentifier:@"" forAnnotation:<#(nonnull id)#>];
// 选中指定大头针
[mapView selectAnnotation:<#(nonnull id)#> animated:<#(BOOL)#>];
// 取消选中指定大头针
[mapView deselectAnnotation:<#(nullable id)#> animated:<#(BOOL)#>];
// 获取所有选中的大头针
NSArray> *selectAniArr=mapV.selectedAnnotations;
// 大头针视图rect(readOnly)
CGRect anRect=mapV.annotationVisibleRect;
// 显示大头针
[mapV showAnnotations:@[] animated:true];
协议 (自定义大头针必须 遵守)
@protocol MKAnnotation
@property (nonatomic, readonly) CLLocationCoordinate2D coordinate; // 地理坐标
@optional
@property (nonatomic, readonly, copy) NSString *title; // 标题
@property (nonatomic, readonly, copy) NSString *subtitle; // 副标题
- (void)setCoordinate:(CLLocationCoordinate2D)newCoordinate; // 拖动时调用
@end
MKAnnotationView
// 创建可复用
MKAnnotationView *aniView=[[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:@"system"];
// 获取复用标识符(readOnly)
NSString *reuseIdentifier=aniView.reuseIdentifier;
// 大头针
id ani=aniView.annotation;
// 大头针图片
[aniView setImage:[UIImage imageNamed:@""]];
// 设置大头针偏移量
[aniView setCenterOffset:CGPointMake(0, 0)];
// 设置气泡偏移量
[aniView setCalloutOffset:CGPointMake(0, 0)];
// 是否可点击(默认:false)
@property (nonatomic, getter=isEnabled) BOOL enabled;
// 是否允许高亮(默认:false)
@property (nonatomic, getter=isHighlighted) BOOL highlighted;
// 是否选中(默认:false)
@property (nonatomic, getter=isSelected) BOOL selected;
[aniView setSelected:true animated:true];
// 是否显示气泡(显示则必须有title)
@property (nonatomic) BOOL canShowCallout;
// 是否可拖拽
@property (nonatomic, getter=isDraggable) BOOL draggable;
// 拖拽状态
@property (nonatomic) MKAnnotationViewDragState dragState;
[aniView setDragState:MKAnnotationViewDragStateEnding animated:true];
// 气泡附件视图
@property (strong, nonatomic, nullable) UIView *leftCalloutAccessoryView;
@property (strong, nonatomic, nullable) UIView *rightCalloutAccessoryView;
@property (nonatomic, strong, nullable) UIView *detailCalloutAccessoryView;
// 用于覆写(必须调super)
- (void)prepareForReuse;
- (void)prepareForDisplay;
// ?
@property (nonatomic, copy, nullable) NSString *clusteringIdentifier;
// (readOnly)
MKAnnotationView *clusterAnnotationView=aniView.clusterAnnotationView;
@property (nonatomic) MKFeatureDisplayPriority displayPriority;
@property (nonatomic) MKAnnotationViewCollisionMode collisionMode;
拖拽状态
typedef NS_ENUM(NSUInteger, MKAnnotationViewDragState) {
MKAnnotationViewDragStateNone = 0,
MKAnnotationViewDragStateStarting,
MKAnnotationViewDragStateDragging,
MKAnnotationViewDragStateCanceling,
MKAnnotationViewDragStateEnding
}
MKPinAnnotationView:MKAnnotationView
// 大头针是否从天而降
aniView.animatesDrop=true;
// 大头针颜色
aniView.pinTintColor=[UIColor yellowColor];
1.2 Overlay覆盖物
折线
// 1. 添加覆盖物
// 点数据
CLLocationCoordinate2D *coor = malloc(sizeof(CLLocationCoordinate2D)*5);
for (int i=0; i<5; i++) {
CLLocationCoordinate2D po = CLLocationCoordinate2DMake(39.23+i*0.01, 116.112+i*0.01);
coor[i]=po;
}
// 创建一个折线
MKPolyline * line = [MKPolyline polylineWithCoordinates:coor count:5];
[mapV addOverlay:line];
// 2. 重新绘制覆盖物
// 覆盖物绘制的代理
-(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id)overlay{
// 折线覆盖物提供者
MKPolylineRenderer * render = [[MKPolylineRenderer alloc]initWithPolyline:overlay];
// 设置线宽
render.lineWidth=3;
// 设置颜色
render.strokeColor=[UIColor redColor];
return render;
}
圆
// 1. 添加覆盖物
MKCircle * cirle = [MKCircle circleWithCenterCoordinate:CLLocationCoordinate2DMake(39, 116) radius:500];
[mapV addOverlay:cirle];
// 2. 绘制覆盖物
// 覆盖物绘制的代理
-(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id)overlay{
MKCircleRenderer * render=[[MKCircleRenderer alloc]initWithCircle:overlay];
// 宽
render.lineWidth=3;
// 填充颜色
render.fillColor=[UIColor greenColor];
// 边框颜色
render.strokeColor=[UIColor redColor];
return render;
}
多边形
// 1. 添加覆盖物
CLLocationCoordinate2D *coor;
coor = malloc(sizeof(CLLocationCoordinate2D)*6);
for (int i=0; i<5; i++) {
CLLocationCoordinate2D po = CLLocationCoordinate2DMake(36+i*0.01, 116+((i/3==0)?0.1:-0.1));
coor[i]=po;
}
coor[5]=CLLocationCoordinate2DMake(36, 116);
MKPolygon * gon = [MKPolygon polygonWithCoordinates:coor count:6];
[mapV addOverlay:gon];
// 2. 绘制覆盖物
-(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id)overlay{
MKPolygonRenderer * render = [[MKPolygonRenderer alloc]initWithPolygon:overlay];
render.lineWidth=3;
render.strokeColor=[UIColor redColor];
return render;
}
Overlay覆盖物
//
NSArray *overArr=mapV.overlays; // 获取所有覆盖物(readOnly)
// 获取覆盖物render
MKOverlayRenderer *overRender=[mapV rendererForOverlay:<#(nonnull id)#>];
NSArray *overAr=[mapV overlaysInLevel:MKOverlayLevelAboveRoads];
// 替换/插入/添加/移除覆盖物
[mapV exchangeOverlay:<#(nonnull id)#> withOverlay:<#(nonnull id)#>];
[mapV exchangeOverlayAtIndex:<#(NSUInteger)#> withOverlayAtIndex:<#(NSUInteger)#>];
[mapV insertOverlay:<#(nonnull id)#> atIndex:0];
[mapV insertOverlay:<#(nonnull id)#> atIndex:0 level:MKOverlayLevelAboveRoads];
[mapV insertOverlay:<#(nonnull id)#> aboveOverlay:<#(nonnull id)#>];
[mapV insertOverlay:<#(nonnull id)#> belowOverlay:<#(nonnull id)#>];
[mapV addOverlays:<#(nonnull NSArray> *)#>];
[mapV addOverlay:<#(nonnull id)#>];
[mapV addOverlay:<#(nonnull id)#> level:MKOverlayLevelAboveRoads];
/*
typedef NS_ENUM(NSInteger, MKOverlayLevel) {
MKOverlayLevelAboveRoads = 0, // 覆盖物在道路上
MKOverlayLevelAboveLabels // 覆盖物在标签上
}
*/
[mapV removeOverlay:<#(nonnull id)#>];
[mapV removeOverlays:<#(nonnull NSArray> *)#>];
自定义覆盖物必须遵守
1.3 MKMapViewDelegate
[mapView setDelegate:self]; // MKMapViewDelegate
// 地图将要加载时调用
-(void)mapViewWillStartLoadingMap:(MKMapView *)mapView{}
// 地图加载完成后调用
-(void)mapViewDidFinishLoadingMap:(MKMapView *)mapView{}
// 地图加载失败后调用
-(void)mapViewDidFailLoadingMap:(MKMapView *)mapView withError:(NSError *)error{}
// 地图将要绘制时调用
-(void)mapViewWillStartRenderingMap:(MKMapView *)mapView{}
// 地图绘制完后调用
-(void)mapViewDidFinishRenderingMap:(MKMapView *)mapView fullyRendered:(BOOL)fullyRendered{}
// 地图显示位置将要改变时调用
-(void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated{}
// 地图显示位置改变后调用
-(void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated{}
// 添加大头针后调用
-(void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views{}
// 自定义大头针
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation{}
// 选中某一大头针
-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view{}
// 取消选中某一大头针
-(void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view{}
// 点击气泡中的附件后调用
-(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control{}
// 大头针的拖动位置改变后调用
-(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view didChangeDragState:(MKAnnotationViewDragState)newState fromOldState:(MKAnnotationViewDragState)oldState{}
/*
typedef NS_ENUM(NSUInteger, MKAnnotationViewDragState) {
MKAnnotationViewDragStateNone = 0, // 初始状态
MKAnnotationViewDragStateStarting, // 开始拖动时
MKAnnotationViewDragStateDragging, // 正在拖动
MKAnnotationViewDragStateCanceling, // 取消拖动
MKAnnotationViewDragStateEnding // 结束拖动
};
*/
// 自定义覆盖物
-(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id)overlay{}
// 添加覆盖物后调用
-(void)mapView:(MKMapView *)mapView didAddOverlayRenderers:(NSArray *)renderers{}
// ?
-(MKClusterAnnotation *)mapView:(MKMapView *)mapView clusterAnnotationForMemberAnnotations:(NSArray> *)memberAnnotations{}
// 将要定位用户位置时调用
-(void)mapViewWillStartLocatingUser:(MKMapView *)mapView{}
// 停止定位用户位置后调用
-(void)mapViewDidStopLocatingUser:(MKMapView *)mapView{}
// 定位用户位置失败后调用
-(void)mapView:(MKMapView *)mapView didFailToLocateUserWithError:(NSError *)error{}
// 用户位置更新时调用
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{}
// 改变用户定位模式后调用
-(void)mapView:(MKMapView *)mapView didChangeUserTrackingMode:(MKUserTrackingMode)mode animated:(BOOL)animated{}
// ?
MKCoordinateRegion region=[mapV regionThatFits:MKCoordinateRegionMake(CLLocationCoordinate2DMake(36, 116), MKCoordinateSpanMake(1, 1))];
// ?
MKMapRect mapRect=[mapV mapRectThatFits:MKMapRectMake(0, 0, 30, 30)];
MKMapRect mapRect=[mapV mapRectThatFits:MKMapRectMake(0, 0, 30, 30) edgePadding:UIEdgeInsetsZero];
// ?
MKMapRect mapRect=[mapV visibleMapRect];
[mapV setVisibleMapRect:[MKMapRectMake(0, 0, 30, 30)]];
[mapV setVisibleMapRect:MKMapRectMake(0, 0, 30, 30) animated:true];
[mapV setVisibleMapRect:MKMapRectMake(0, 0, 30, 30) edgePadding:UIEdgeInsetsZero animated:true];
/*
typedef struct {
MKMapPoint origin;
MKMapSize size;
} MKMapRect;
typedef struct {
double x;
double y;
} MKMapPoint;
typedef struct {
double width;
double height;
} MKMapSize;
typedef struct {
MKMapPoint origin;
MKMapSize size;
} MKMapRect;
*/
// ?
MKMapCamera *mapCamera=[mapV camera];
[mapV setCamera:[MKMapCamera cameraLookingAtCenterCoordinate:CLLocationCoordinate2DMake(36, 116) fromDistance:CLLocationDistanceMax pitch:0.5 heading:kCFLocaleLanguageDirectionLeftToRight]];
1.4. 苹果原生地图App
//
[[CLGeocoder new]geocodeAddressString:@"山西" completionHandler:^(NSArray * _Nullable placemarks, NSError * _Nullable error) {
CLPlacemark *placeMark=[placemarks firstObject];
// 跳转到苹果原生App,并标注一个点
MKPlacemark *mPlaceMark=[[MKPlacemark alloc]initWithPlacemark:placeMark];
MKMapItem *mItem=[[MKMapItem alloc]initWithPlacemark:mPlaceMark];
[mItem openInMapsWithLaunchOptions:@{MKLaunchOptionsMapTypeKey:@(MKMapTypeStandard)}];
// 添加多个标注
[MKMapItem openMapsWithItems:@[mItem,mItem2] launchOptions:@{MKLaunchOptionsMapTypeKey:@(MKMapTypeStandard)];
// 导航
[MKMapItem openMapsWithItems:@[mItem,mItem2] launchOptions:@{MKLaunchOptionsMapTypeKey:@(MKMapTypeStandard),MKLaunchOptionsDirectionsModeKey:MKLaunchOptionsDirectionsModeDriving}];
}];
2. 定位
定位
{
CLLocationManager *locationManger; //(必须是全局的,否则出现请求定位弹窗就消失)
}
-(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
locationManger=nil;
}
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
//
locationManger.delegate=self;
// 定位精度(越精确越耗电,定位速度越慢)
locationManger.desiredAccuracy=kCLLocationAccuracyNearestTenMeters;
/**
kCLLocationAccuracyBest:最精确定位
kCLLocationAccuracyNearestTenMeters:十米误差范围
kCLLocationAccuracyHundredMeters:百米误差范围
kCLLocationAccuracyKilometer:千米误差范围
kCLLocationAccuracyThreeKilometers:三千米误差范围
*/
locationManger.distanceFilter=50; // 每隔50m定位一次
[locationManger startUpdatingLocation]; // 开始定位
}
-(void)viewDidLoad{
[super viewDidLoad];
// 定位管理器
locationManger=[CLLocationManager new];
if(![CLLocationManager locationServicesEnabled]){
NSLog(@"定位 服务关闭");
return;
}else if ([CLLocationManager authorizationStatus]==kCLAuthorizationStatusNotDetermined){
/**
kCLAuthorizationStatusNotDetermined: 用户尚未做出决定是否启用定位服务
kCLAuthorizationStatusRestricted: 没有获得用户授权使用定位服务,可能用户没有自己禁止访问授权
kCLAuthorizationStatusDenied :用户已经明确禁止应用使用定位服务或者当前系统定位服务处于关闭状态
kCLAuthorizationStatusAuthorizedAlways: 应用获得授权可以一直使用定位服务,即使应用不在使用状态
kCLAuthorizationStatusAuthorizedWhenInUse: 使用此应用过程中允许访问定位服务
*/
// 请求定位授权
[locationManger requestWhenInUseAuthorization]; // 需在info.plist中+NSLocationWhenInUseUsageDescription
// [locationManger requestAlwaysAuthorization]; // 需在info.plist中+NSLocationAlwaysUsageDescription
}
}
// 地址更新后回调
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
[manager stopUpdatingLocation];
CLLocation *location=[locations firstObject];
CLLocationCoordinate2D loc=location.coordinate;
// 反地理编码
CLGeocoder *myGeocoder = [CLGeocoder new];
// 坐标转地名
[myGeocoder reverseGeocodeLocation:[[CLLocation alloc]initWithLatitude:loc.latitude longitude:loc.longitude] completionHandler:^(NSArray * _Nullable placemarks, NSError * _Nullable error) {
//
CLPlacemark *placeMark=[placemarks firstObject];
CLLocation *location=[placeMark location];
_currentLocation=location;
//
}];
}
监听方向
[locationManger startUpdatingHeading]; // 开始监听用户方向
[locationManger stopUpdatingHeading]; // 停止监听用户方向
-(void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading{
}
监听区域
[locationManger startMonitoringForRegion:]; // 监听 进入/离开某区域
[locationManger stopMonitoringForRegion:]; // stop 监听
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region{
}
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region{
}
2.1 地理 编码和反编码
放在didUpdateLocations方法中获取地址信息
//
CLGeocoder *myGeocoder = [CLGeocoder new];
// 坐标转地名
[myGeocoder reverseGeocodeLocation:[[CLLocation alloc]initWithLatitude:39.54 longitude:116.0] completionHandler:^(NSArray * _Nullable placemarks, NSError * _Nullable error) {
//
CLPlacemark *placeMark=[placemarks firstObject];
NSDictionary *addressDic=placeMark.addressDictionary; // detail {"Name":地名,@"State":省名,@"City":市名,@"Country":国家}
}];
// 地名转坐标
[myGeocoder geocodeAddressString:@"北京" completionHandler:^(NSArray *placeMarks, NSError *error) {
//
if ([placeMarks count] > 0 && error == nil) {
// 拿到第一个坐标
CLPlacemark *placeMark=[placeMarks firstObject];
CLLocation *location=placeMark.location; // location
/**
CLRegion *region=placeMark.region; // region
NSDictionary *addressDic=placeMark.addressDictionary; // detail
NSString *name=placeMark.name; // 地名
NSString *thoroughfare=placeMark.thoroughfare; // 街道
NSString *subThoroughfare=placeMark.subThoroughfare; // 街道相关信息,例如门牌等
NSString *locality=placeMark.locality; // 城市
NSString *subLocality=placeMark.subLocality; // 城市相关信息,例如标志性建筑
NSString *administrativeArea=placeMark.administrativeArea; // 州
NSString *subAdministrativeArea=placeMark.subAdministrativeArea; // 其他行政区域信息
NSString *postalCode=placeMark.postalCode; // 邮编
NSString *ISOcountryCode=placeMark.ISOcountryCode; // 国家编码
NSString *country=placeMark.country; // 国家
NSString *inlandWater=placeMark.inlandWater; // 水源、湖泊
NSString *ocean=placeMark.ocean; // 海洋
NSArray *areasOfInterest=placeMark.areasOfInterest; // 关联的或利益相关的地标
*/
//
NSLog(@"获得地理编码经度 = %f", placeMark.location.coordinate.longitude);
NSLog(@"获得地理编码纬度 = %f", placeMark.location.coordinate.latitude);
}else if ([placeMarks count] == 0 && error == nil) {
NSLog(@"Found no placeMarks.");
}else if (error != nil) {
NSLog(@"An error occurred = %@", error);
}
}];
1.导航---获取路线
// 1.创建出发和结束节点
// 设置导航起始经纬度
CLLocationCoordinate2D fromcoor=CLLocationCoordinate2DMake(36, 116);
CLLocationCoordinate2D tocoor = CLLocationCoordinate2DMake(36.8, 116.8);
// 创建出发点和目的点信息
MKPlacemark *fromPlace = [[MKPlacemark alloc] initWithCoordinate:fromcoor addressDictionary:nil];
MKPlacemark *toPlace = [[MKPlacemark alloc]initWithCoordinate:tocoor addressDictionary:nil];
// 创建出发节点和目的地节点
MKMapItem * fromItem = [[MKMapItem alloc]initWithPlacemark:fromPlace];
MKMapItem * toItem = [[MKMapItem alloc]initWithPlacemark:toPlace];
// 2.创建导航搜索请求
MKDirectionsRequest *request = [[MKDirectionsRequest alloc]init];
request.source=fromItem; // 出发节点
request.destination=toItem; // 结束节点
request.requestsAlternateRoutes=YES; //
// 3.开始检索(结果会返回在block中)
MKDirections *directions = [[MKDirections alloc]initWithRequest:request];
[directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) {
if (error) {
NSLog(@"error:%@",error);
}else{
// 4.获取到路线( 绘制 标注和路线)
// 提取导航线路结果中的一条线路
MKRoute *route =response.routes[0];
// 提取线路中的每一步
NSArray * stepArray = [NSArray arrayWithArray:route.steps];
// 遍历每一步
for (int i=0; i)overlay{
MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithPolyline:overlay];
renderer.strokeColor = [UIColor redColor];
renderer.lineWidth = 4.0;
return renderer;
}
// 标注
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation{
MKPinAnnotationView * view= [[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:@"anno"];
view.canShowCallout=YES;
return view;
}
- POI检索
周边搜索(根据关键字和搜索范围)
-(void)search:(NSString *)searchStr{
// 周边搜索 请求类(设置条件进行查询)
MKLocalSearchRequest *localSearchRequest = [[MKLocalSearchRequest alloc] init];
// 设置 搜索范围
MKCoordinateSpan span = MKCoordinateSpanMake(0.6250, 0.6250);
MKCoordinateRegion region = MKCoordinateRegionMake(_currentLocation.coordinate, span);
localSearchRequest.region = region;
// 设置 搜索关键词
localSearchRequest.naturalLanguageQuery = searchStr;
// 周边搜索类
MKLocalSearch *localSearch = [[MKLocalSearch alloc] initWithRequest:localSearchRequest];
// 开始搜索
[localSearch startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) {
NSLog(@"count:%ld",response.mapItems.count);
if (error){
NSLog(@"error:%@",error);
}else{ NSLog(@"name:%@,\nthoroughfare:%@,\nsubThoroughfare:%@,\nlocality:%@,\nsubLocality:%@,\nadministrativeArea:%@,\nsubAdministrativeArea:%@,\ncountry:%@,\ninlandWater:%@,\nocean:%@",mapItem.placemark.name,mapItem.placemark.thoroughfare,mapItem.placemark.subThoroughfare,mapItem.placemark.locality,mapItem.placemark.subLocality,mapItem.placemark.administrativeArea,mapItem.placemark.subAdministrativeArea,mapItem.placemark.country,mapItem.placemark.inlandWater,mapItem.placemark.ocean);
}
}
}];
}
4. 相关类
4.1 CLLocationManager
CLLocationManager 位置管理者
// 获取 当前定位是否授权
CLAuthorizationStatus status=[CLLocationManager authorizationStatus];
/*
// 用户还没选择是否授权
kCLAuthorizationStatusNotDetermined
// 用户拒绝授权
kCLAuthorizationStatusDenied
// 始终允许
kCLAuthorizationStatusAuthorizedAlways
// 使用期间允许
kCLAuthorizationStatusAuthorizedWhenInUse
// 应用拒绝使用定位
kCLAuthorizationStatusRestricted
*/
// 设备是否支持定位服务
BOOL isCanLocation=[CLLocationManager locationServicesEnabled];
// 请求用户位置权限---使用期间
[locationManger requestWhenInUseAuthorization];
// 请求用户位置权限---始终
[locationManger requestAlwaysAuthorization];
// 请求一次位置
[locationManger requestLocation];
// 设置 位置更新的模式
[locationManger setActivityType:CLActivityTypeOther];
/*
CLActivityTypeOther = 1 未知
CLActivityTypeAutomotiveNavigation 车辆导航模式
CLActivityTypeFitness 步行模式
CLActivityTypeOtherNavigation 其他交通工具模式
*/
// 设置 最小的更新距离为 50m(低于50不更新)
[locationManger setDistanceFilter:50];
// 设置 最小的方向改变角度,低于角度不更新
[locationManger setHeadingFilter:10];
// 设置 定位精准度(越精确越费电)
[locationManger setDesiredAccuracy:kCLLocationAccuracyBest];
/*
kCLLocationAccuracyBestForNavigation 最高精确
kCLLocationAccuracyBest 高精确
kCLLocationAccuracyNearestTenMeters 10米
kCLLocationAccuracyHundredMeters 百米
kCLLocationAccuracyKilometer 千米
kCLLocationAccuracyThreeKilometers 三公里
*/
// 设置 位置更新是否自动停止(位置不变时停止更新)
[locationManger setPausesLocationUpdatesAutomatically:true];
// 设置导航方向,以正北为参照物
[locationManger setHeadingOrientation:CLDeviceOrientationPortrait];
/*
typedef NS_ENUM(int, CLDeviceOrientation) {
CLDeviceOrientationUnknown = 0 , // 方向未知
CLDeviceOrientationPortrait, // 纵向模式
CLDeviceOrientationPortraitUpsideDown, // 纵向倒置模式
CLDeviceOrientationLandscapeLeft, // 左向横向模式
CLDeviceOrientationLandscapeRight, // 右向横向模式
CLDeviceOrientationFaceUp, // 水平屏幕向上模式
CLDeviceOrientationFaceDown // 水平屏幕下模式
};
*/
// 设置 立刻隐藏方向标(方向改变后稳定前 会出现)
[locationManger dismissHeadingCalibrationDisplay];
// 设置 是否允许后台刷新
[locationManger setAllowsBackgroundLocationUpdates:true];
// 设置 处于后台使用位置时手机上方是否显示正在使用(默认:false)
[locationManger setShowsBackgroundLocationIndicator:true];
// ?
[locationManger requestStateForRegion:[CLRegion new]];
位置更新
// 设备是否支持监测位置更新变换
BOOL isCanMonitor=[CLLocationManager significantLocationChangeMonitoringAvailable];
// 获取 最后更新的位置(readOnly)
CLLocation location=locationManger.location;
// 开始/结束监测位置变化
[locationManger startUpdatingLocation];
[locationManger stopUpdatingLocation];
// 开始/结束监测?变化
[locationManger startMonitoringSignificantLocationChanges];
[locationManger stopMonitoringSignificantLocationChanges];
导航
// 设备是否支持heading航向(模拟器不支持)
BOOL isCanHeading=[CLLocationManager headingAvailable];
// 获取 最后更新的航向(readOnly)
CLHeading *heading=locationManger.heading;
// 开始/结束监测方向变化
[locationManger startUpdatingHeading];
[locationManger stopUpdatingHeading];
监测区域
// 获取 是否支持监测指定区域的位置更新变换
BOOL isCanMonitorRegion=[CLLocationManager isMonitoringAvailableForClass:nil];
// 获取 最大的监测区域范围 (readOnly)
CLLocationDistance distance=locationManger.maximumRegionMonitoringDistance;
// 获取 所有监测的区域 (readOnly)
NSSet regionMonSet=locationManger.monitoredRegions;
// 获取 所有区域 (readOnly)
NSSet regionSet=locationManger.rangedRegions;
// 开始/结束监测区域变化
[locationManger startMonitoringForRegion:[CLRegion new]];
[locationManger stopMonitoringForRegion:[CLRegion new]];
// 开始/结束监测指定区域的信号坐标
[locationManger startRangingBeaconsInRegion:[CLBeaconRegion new]];
[locationManger stopRangingBeaconsInRegion:[CLBeaconRegion new]];
延迟更新
// 获取 是否延迟位置更新
BOOL isDefre=[CLLocationManager deferredLocationUpdatesAvailable];
// 设置 允许延迟更新
[locationManger allowDeferredLocationUpdatesUntilTraveled:10 timeout:2];
// 设置 不允许延迟更新位置
[locationManger disallowDeferredLocationUpdates];
dele
//
[locationManger setDelegate:self];
// 定位出现错误后调用
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{}
位置更新
// 调用startUpdatingLocation后,更新位置后会调用此方法
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{}
// 当暂停更新位置后调用
-(void)locationManagerDidPauseLocationUpdates:(CLLocationManager *)manager{}
// 当恢复更新位置后调用
-(void)locationManagerDidResumeLocationUpdates:(CLLocationManager *)manager{}
导航
// 调用startUpdatingHeading后,更新方向后调用此方法
-(void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading{}
// 在改变方向稳定之前是否显示校准视图
-(BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager *)manager{}
区域监测
// 当用户进入指定区域后调用
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region{}
// 当用户离开指定区域后调用
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region{}
// 当检测指定区域失败后调用
-(void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error{}
// 调用startMonitoringForRegion:成功后调用
-(void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region{}
// 在监测区域状态改变后调用
-(void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region{}
// 当一个新的信号在指定区域出现时调用
-(void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region{}
// 当指定区域的信号发生错误时调用
-(void)locationManager:(CLLocationManager *)manager rangingBeaconsDidFailForRegion:(CLBeaconRegion *)region withError:(NSError *)error{}
// 监测到之前访问过该位置时调用
-(void)locationManager:(CLLocationManager *)manager didVisit:(CLVisit *)visit{}
// 当位置权限改变后调用
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status{}
// 停止延迟更新后调用
-(void)locationManager:(CLLocationManager *)manager didFinishDeferredUpdatesWithError:(NSError *)error{}
4.2 CLLocation
CLLocation 位置信息
// 新建
CLLocation *loction=[[CLLocation alloc]initWithLatitude:180 longitude:100];
CLLocation *loction=[[CLLocation alloc]initWithCoordinate:CLLocationCoordinate2DMake(180, 80) altitude:100 horizontalAccuracy:1 verticalAccuracy:1 timestamp:[NSDate date]];
CLLocation *loction=[[CLLocation alloc]initWithCoordinate:CLLocationCoordinate2DMake(100, 100) altitude:100 horizontalAccuracy:1 verticalAccuracy:1 course:1 speed:1 timestamp:[NSDate date]];
CLLocation location=locationManger.location; // 获取 最后更新的位置(readOnly)
// 经纬度(readOnly)
CLLocationCoordinate2D loct=loction.coordinate;
// 海拔(readOnly)
CLLocationDistance altitude=location.altitude;
// 水平精度---容错半径(readOnly)
CLLocationAccuracy hA=location.horizontalAccuracy;
// 纵向精度---容错半径(readOnly)
CLLocationAccuracy vA=loction.verticalAccuracy;
// 设备的前进方向与正北的角度---0~359.9(readOnly)
CLLocationDirection course=location.course;
// 速度---m/s(readOnly)
CLLocationSpeed speed=location.speed;
// 最后更新位置被确定时的时间戳(readOnly)
NSDate *date=location.timestamp;
// 楼层数(readOnly)
CLFloor floor=location.floor;
// 两个位置之间的距离
CLLocationDistance distan=[location distanceFromLocation:[CLLocation new]];
typedef struct {
CLLocationDegrees latitude; // 纬度
CLLocationDegrees longitude; // 经度
} CLLocationCoordinate2D;
4.3 CLGeocoder
CLGeocoder 编码
CLGeocoder *geocoder=[CLGeocoder new];
// 是否正在进行地理编码
BOOL isGeoing=[geocoder isGeocoding];
// 中止地理编码
[geocoder cancelGeocode];
// 坐标转地名
[geocoder reverseGeocodeLocation:[CLLocation new] completionHandler:^(NSArray * _Nullable placemarks, NSError * _Nullable error) {
//
}];
[geocoder reverseGeocodeLocation:[CLLocation new] preferredLocale:[NSLocale new] completionHandler:^(NSArray * _Nullable placemarks, NSError * _Nullable error) {
}];
// 地名转坐标
[geocoder geocodeAddressString:@"北京" completionHandler:^(NSArray * _Nullable placemarks, NSError * _Nullable error) {
}];
[geocoder geocodeAddressString:@"" inRegion:[CLRegion new] completionHandler:^(NSArray * _Nullable placemarks, NSError * _Nullable error) {
}];
[geocoder geocodeAddressString:@"" inRegion:[CLRegion new] preferredLocale:[NSLocale new] completionHandler:^(NSArray * _Nullable placemarks, NSError * _Nullable error) {
}];
[geocoder geocodeAddressDictionary:@{} completionHandler:^(NSArray * _Nullable placemarks, NSError * _Nullable error) {
}];
[geocoder geocodePostalAddress:[CNPostalAddress new] completionHandler:^(NSArray * _Nullable placemarks, NSError * _Nullable error) {
}];
[geocoder geocodePostalAddress:[CNPostalAddress new] preferredLocale:[NSLocale new] completionHandler:^(NSArray * _Nullable placemarks, NSError * _Nullable error) {
}];
4.4 CLHeading 导航
// 获取 最后更新的航向(readOnly)
CLHeading *heading=locationManger.heading;
// 设备的朝向---0~359.9 0为北磁极(readOnly)
CLLocationDirection magneticHeading=heading.magneticHeading;
// 设备的真实朝向---0~359.9 0为北极(readOnly)
CLLocationDirection trueHeading=heading.trueHeading;
// 方向偏差(readOnly)
CLLocationDirection headingAccuracy=heading.headingAccuracy;
// x(readOnly)
CLHeadingComponentValue x=heading.x;
// y(readOnly)
CLHeadingComponentValue y=heading.y;
// z(readOnly)
CLHeadingComponentValue z=heading.z;
// 当前导航的时间戳(readOnly)
NSDate *timestamp=heading.timestamp;
4.5 CLPlacemark
CLPlacemark 地理坐标信息
CLPlacemark *placeMark=[[CLPlacemark alloc]initWithPlacemark:[CLPlacemark new]];
// 位置(readOnly)
CLLocation *loc=placeMark.location;
// 区域(readOnly)
CLRegion *region=placeMark.region;
// 时区(readOnly)
NSTimeZone *timeZone=placeMark.timeZone;
// 详细信息dic(readOnly)
NSDictionary *addressDic=placeMark.addressDictionary;
// dic中
//
NSString *name=placeMark.name;
// 街道
NSString *tho=placeMark.thoroughfare;
NSString *subTho=placeMark.subThoroughfare;
// 城市
NSString *locality=placeMark.locality;
NSString *subLocality=placeMark.subLocality;
NSString *ad=placeMark.administrativeArea;
NSString *subAd=placeMark.subAdministrativeArea;
NSString *posta=placeMark.postalCode;
NSString *iso=placeMark.ISOcountryCode;
// 国家
NSString *country=placeMark.country;
NSString *inland=placeMark.inlandWater;
NSString *ocan=placeMark.ocean;
NSArray *areaArr=placeMark.areasOfInterest;
4.6 导航相关
MKPlacemark
// 地点信息类
// MKPlacemark : CLPlacemark
MKPlacemark placeM=[[MKPlacemark alloc]initWithCoordinate:CLLocationCoordinate2DMake(36, 116) addressDictionary:@{}];
// 国家编码(readOnly)
NSString *countryCode=placeM.countryCode;
MKMapItem
// 地点节点类
// MKMapItem: NSObject
// 根据placemark创建
MKMapItem *mapItem=[[MKMapItem alloc]initWithPlacemark:placeM];
// 根据当前位置创建
MKMapItem *mapItem=[MKMapItem mapItemForCurrentLocation];
// placemark地点信息(readOnly)
MKPlacemark *placemark=mapItem.placemark;
// 是否是当前位置
BOOL isCurrentL=mapItem.isCurrentLocation;
// 节点名称
@property (nonatomic, copy) NSString *name;
// 电话号码
@property (nonatomic, copy) NSString *phoneNumber;
// 网址
@property (nonatomic, strong) NSURL *url;
// 时区
@property (nonatomic, copy, nullable) NSTimeZone *timeZone;
MKDirectionsRequest
// 导航请求类(设置查询条件(出发/结束地址等)进行查询)
@interface MKDirectionsRequest : NSObject
// 出发节点
- (MKMapItem *)source;
- (void)setSource:(MKMapItem *)source;
// 结束节点
- (MKMapItem *)destination;
- (void)setDestination:(MKMapItem *)destination;
// 路线检索类型
@property (nonatomic) MKDirectionsTransportType transportType;
typedef NS_OPTIONS(NSUInteger, MKDirectionsTransportType) {
MKDirectionsTransportTypeAutomobile = 1 << 0, // 适合驾车时导航
MKDirectionsTransportTypeWalking = 1 << 1, // 适合步行时导航
MKDirectionsTransportTypeAny = 0x0FFFFFFF// 任何情况(默认)
};
// 是否搜索多条路线
@property (nonatomic) BOOL requestsAlternateRoutes;
// 出发日期
@property (nonatomic, copy, nullable) NSDate *departureDate;
// 结束日期
@property (nonatomic, copy, nullable) NSDate *arrivalDate;
@end
MKDirections
// 计算路线数据类
@interface MKDirections : NSObject
// 创建
- (instancetype)initWithRequest:(MKDirectionsRequest *)request;
// 开始计算获取线路信息
- (void)calculateDirectionsWithCompletionHandler:(MKDirectionsHandler)completionHandler;
// 开始计算时间信息
- (void)calculateETAWithCompletionHandler:(MKETAHandler)completionHandler;
// 取消
- (void)cancel;
// 是否正在计算
@property (nonatomic, readonly, getter=isCalculating) BOOL calculating;
@end
MKETAResponse
// 时间信息结果类
@interface MKETAResponse : NSObject
// 起点
@property (nonatomic, readonly) MKMapItem *source;
// 终点
@property (nonatomic, readonly) MKMapItem *destination;
// 耗时
@property (nonatomic, readonly) NSTimeInterval expectedTravelTime;
//
@property (nonatomic, readonly) CLLocationDistance distance;
//
@property (nonatomic, readonly) NSDate *expectedArrivalDate;
//
@property (nonatomic, readonly) NSDate *expectedDepartureDate;
//
@property (nonatomic, readonly) MKDirectionsTransportType transportType ;
@end
MKDirectionsResponse
// 线路信息结果类
@interface MKDirectionsResponse : NSObject
// 起点
@property (nonatomic, readonly) MKMapItem *source;
// 终点
@property (nonatomic, readonly) MKMapItem *destination;
// 线路规划数组(存放所有的线路)
@property (nonatomic, readonly) NSArray *routes;
@end
MKRoute
// 整条线路类
@interface MKRoute : NSObject
// 线路名
@property (nonatomic, readonly) NSString *name;
// 线路注意事项
@property (nonatomic, readonly) NSArray *advisoryNotices;
// 线路距离
@property (nonatomic, readonly) CLLocationDistance distance;
// 线路耗时
@property (nonatomic, readonly) NSTimeInterval expectedTravelTime;
// 线路检索类型
@property (nonatomic, readonly) MKDirectionsTransportType transportType;
// 线路覆盖物
@property (nonatomic, readonly) MKPolyline *polyline;
// 线路详情数组(存放所有部分线路)
@property (nonatomic, readonly) NSArray *steps;
@end
MKRouteStep 每一条线路信息
@interface MKRouteStep : NSObject
// 线路节点信息
@property (nonatomic, readonly) NSString *instructions;
// 线路节点注意事项
@property (nonatomic, readonly) NSString *notice;
// 线路覆盖物
@property (nonatomic, readonly) MKPolyline *polyline;
// 线路距离
@property (nonatomic, readonly) CLLocationDistance distance;
// 线路导航类型
@property (nonatomic, readonly) MKDirectionsTransportType transportType;
@end