- (void)startUpdatingLocation;
当调用了startUpdatingLocation方法后,就开始不断地请求、刷新用户的位置,一旦请求到用户位置就会调用代理的下面方法
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations;
复制代码
locations参数里面装着CLLocation对象
停止更新用户位置
- (void) stopUpdatingLocation;
复制代码
判断定位功能是否可用(为了严谨起见,最好在使用定位功能前进行判断)
+ (BOOL)locationServicesEnabled;
复制代码
监听设备朝向
-(void)startUpdatingHeading(如试例代码中的指南针的实现)
复制代码
区域监听(监听进出某个区域)
-(void)requestStateForRegion:region;
复制代码
[self.lM startUpdatingLocation];
复制代码
[self.lM startUpdatingHeading];
复制代码
- 区域监听(监听进出某个区域)
[self.lM requestStateForRegion:region]
复制代码
代理方法
更新位置后调用
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations;
授权状态改变时调用
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
获取手机朝向时调用
-(void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
区域监听的代理方法
进入区域时调用:-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
离开区域时调用:-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
监听是否在某个区域的状态:-(void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state
* 更新到位置之后调用
* @param manager 位置管理者
* @param locations 位置数组
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
NSLog(@"定位到了");
复制代码
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
NSLog(@"进入区域--%@", region.identifier);
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
NSLog(@"离开区域--%@", region.identifier);
-(void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
NSLog(@"%zd", state);
复制代码
CLLocation
CLLocation用来表示某个位置的地理信息,比如经纬度,海拔等等
@property(readonly, nonatomic) CLLocationCoordinate2D coordinate;
@property(readonly, nonatomic) CLLocationDistance altitude;
路线,航向(取值范围是0.0° ~ 359.9°,0.0°代表真北方向)
@property(readonly, nonatomic) CLLocationDirection course;
移动速度(单位是m/s)
@property(readonly, nonatomic) CLLocationSpeed speed;
计算两个位置之间的距离:
- (CLLocationDistance)distanceFromLocation:(const CLLocation *)location
使用试例:根据移动方向打印出移动的方向和距离
* CLLocationManager对象的代理方法,当用户位置改变的时候调用
* 更新到位置之后调用
* @param manager 位置管理者
* @param locations 位置数组
* is kind of
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
// NSLog(@"定位到了")
* CLLocation 详解
* coordinate : 经纬度
* altitude : 海拔
* course : 航向
* speed
CLLocation *location = [locations lastObject]
// NSLog(@"%@", location)
* 场景演示:打印当前用户的行走方向,偏离角度以及对应的行走距离,
例如:”北偏东 30度 方向,移动了8米”
// 1. 获取方向偏向
NSString *angleStr = nil
switch ((int)location.course / 90) {
case 0:
angleStr = @"北偏东"
break
case 1:
angleStr = @"东偏南"
break
case 2:
angleStr = @"南偏西"
break
case 3:
angleStr = @"西偏北"
break
default:
angleStr = @"跑沟里去了!!"
break
// 2. 偏向角度
NSInteger angle = 0
angle = (int)location.course % 90
// 代表正方向
if (angle == 0) {
NSRange range = NSMakeRange(0, 1)
angleStr = [NSString stringWithFormat:@"正%@", [angleStr substringWithRange:range]]
// 3.移动多少米
double distance = 0
if(_oldL)
distance = [location distanceFromLocation:_oldL]
_oldL = location
// 4. 拼串 打印
// 例如:”北偏东 30度 方向,移动了8米”
NSString *noticeStr = [NSString stringWithFormat:@"%@%zd方向, 移动了%f米", angleStr, angle, distance]
NSLog(@"%@", noticeStr)
复制代码
ios地图开发用户隐私保护(授权)
ios6+
当使用定位时,系统会自动弹出对话框让用户授权。
一旦用户选择了不允许,意味着应用程序以后都无法使用定位。
开发者可以在Info.plist中设置NSLocationUsageDescription说明定位的目的(Privacy - Location Usage Description)
ios8.0+
从ios8.0开始,苹果进一步加强了对用户隐私的保护。
当app想访问用户的隐私时,系统不再自动弹出一个对话框让用户授权.
(1)调用ios8.0的api。主动请求用户授权
-(void)requestAlwaysAuthorization // 请求允许在前后台都能获取用户位置的授权
-(void)requestWhenInUseAuthorization // 请求允许在前台获取用户位置的授权(注意:当设置为前台授权时,通过设置后台模式:location updates后 也可以后台获取定位信息,但是屏幕上方会出现蓝条)
(2)务必在info.plist文件中配置对应的键值, 否则以上请求授权的方法不生效
NSLocationAlwaysUsageDescription : 允许在前后台获取GPS的描述
NSLocationWhenInUseDescription : 允许在前台获取GPS的描述
ios9.0
ios9.0如果当前处于前台授权状态,默认是不可以后台获取用户位置。但可以设置以下属性为YES,就可以继续在后台获取位置,但是在屏幕上方会出现蓝条
@property(assign, nonatomic) BOOL allowsBackgroundLocationUpdates
使用注意:必须设置对应的后台模式:location updates
ios9.0可以单次请求用户位置
-(void)requestLocation
-(void)locationManager:(nonnull CLLocationManager *)manager didUpdateLocations:(nonnull NSArray<CLLocation *> *)locations // 成功调用
-(void)locationManager:(nonnull CLLocationManager *)manager didFailWithError:(nonnull NSError *)error // 失败调用
CLGeocoder
使用CLGeocoder可以完成“地理编码”和“反地理编码”
地理编码:根据给定的地名,获得具体的位置信息(比如经纬度、地址的全称等)
反地理编码:根据给定的经纬度,获得具体的位置信息
地理编码方法
-(void)geocodeAddressString:(NSString *)addressString completionHandler:(CLGeocodeCompletionHandler)completionHandler;
反地理编码方法
-(void)reverseGeocodeLocation:(CLLocation *)location completionHandler:(CLGeocodeCompletionHandler)completionHandler;
CLGeocodeCompletionHandler:反地理编码完成时,就会调用CLGeocodeCompletionHandler
typedef void (^CLGeocodeCompletionHandler)(NSArray *placemarks, NSError *error);
error :当编码出错时(比如编码不出具体的信息)有值
placemarks :里面装着CLPlacemark对象
// 地理编码方案一:直接根据地址进行地理编码(返回结果可能有多个,因为一个地点有重名)
[self.geoC geocodeAddressString:self.addressDetailTV.text completionHandler:^(NSArray<CLPlacemark *> * __nullable placemarks, NSError * __nullable error) {
// 包含区,街道等信息的地标对象
CLPlacemark *placemark = [placemarks firstObject]
// 城市名称
// NSString *city = placemark.locality
// 街道名称
// NSString *street = placemark.thoroughfare
// 全称
NSString *name = placemark.name
self.addressDetailTV.text = [NSString stringWithFormat:@"%@", name]
self.latitudeTF.text = [NSString stringWithFormat:@"%f", placemark.location.coordinate.latitude]
self.longtitudeTF.text = [NSString stringWithFormat:@"%f", placemark.location.coordinate.longitude]
// 地理编码方案二:根据地址和区域两个条件进行地理编码(更加精确)
// [self.geoC geocodeAddressString:self.addressDetailTV.text inRegion:nil completionHandler:^(NSArray<CLPlacemark *> * __nullable placemarks, NSError * __nullable error) {
// // 包含区,街道等信息的地标对象
// CLPlacemark *placemark = [placemarks firstObject]
// self.addressDetailTV.text = placemark.description
// self.latitudeTF.text = [NSString stringWithFormat:@"%f", placemark.location.coordinate.latitude]
// self.longtitudeTF.text = [NSString stringWithFormat:@"%f", placemark.location.coordinate.longitude]
// }]
// 地理编码方案三:
// NSDictionary *addressDic = @{
// (__bridge NSString *)kABPersonAddressCityKey : @"北京",
// (__bridge NSString *)kABPersonAddressStreetKey : @"棠下街"
// }
// [self.geoC geocodeAddressDictionary:addressDic completionHandler:^(NSArray<CLPlacemark *> * __nullable placemarks, NSError * __nullable error) {
// CLPlacemark *placemark = [placemarks firstObject]
// self.addressDetailTV.text = placemark.description
// self.latitudeTF.text = [NSString stringWithFormat:@"%f", placemark.location.coordinate.latitude]
// self.longtitudeTF.text = [NSString stringWithFormat:@"%f", placemark.location.coordinate.longitude]
// }]
复制代码
反地理编码的实现
- (IBAction)decode {
if ([self.latitudeTF.text length] == 0 || [self.longtitudeTF.text length] == 0) {
return;
CLLocation *location = [[CLLocation alloc] initWithLatitude:[self.latitudeTF.text doubleValue] longitude:[self.longtitudeTF.text doubleValue]];
[self.geoC reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * __nullable placemarks, NSError * __nullable error) {
CLPlacemark *placemark = [placemarks firstObject];
NSString *name = placemark.name;
self.addressDetailTV.text = [NSString stringWithFormat:@"%@", name];
复制代码
CLPlacemark
CLPlacemark的字面意思是地标,封装详细的地址位置信息
@property (nonatomic, readonly) CLLocation *location;
@property (nonatomic, readonly) CLRegion *region;
详细的地址信息
@property (nonatomic, readonly) NSDictionary *addressDictionary;
@property (nonatomic, readonly) NSString *name;
@property (nonatomic, readonly) NSString *locality;
MapKit框架的使用
MapKit通过MKMapView来显示地图
地图配型:mapType
MKMapTypeStandard :普通地图(左图)
MKMapTypeSatellite :卫星云图 (中图)
MKMapTypeHybrid :混合模式(普通地图覆盖于卫星云图之上 )
MKMapTypeSatelliteFlyover: 3D立体卫星 (iOS9.0)
MKMapTypeHybridFlyover: 3D立体混合 (iOS9.0)
跟踪显示用户的位置(ios8-地图不会自动滚到用户所在的位置,ios8+地图会自动放大到合适比例,并显示出用户位置)
MKUserTrackingModeNone :不跟踪用户的位置
MKUserTrackingModeFollow :跟踪并在地图上显示用户的当前位置
MKUserTrackingModeFollowWithHeading :跟踪并在地图上显示用户的当前位置,地图会跟随用户的前进方向进行旋转
设置地图显示的区域和位置
设置地图的中心点位置
@property (nonatomic) CLLocationCoordinate2D centerCoordinate;
-(void)setCenterCoordinate:(CLLocationCoordinate2D)coordinate animated:(BOOL)animated;
设置地图的显示区域
@property (nonatomic) MKCoordinateRegion region;
-(void)setRegion:(MKCoordinateRegion)region animated:(BOOL)animated;
typedef struct {
CLLocationCoordinate2D center;
MKCoordinateSpan span;
} MKCoordinateRegion;
MKCoordinateSpan
typedef struct {
CLLocationDegrees latitudeDelta;
CLLocationDegrees longitudeDelta;
} MKCoordinateSpan;
复制代码
MKMapView的代理
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation;
一个位置更改默认只会调用一次,不断监测用户的当前位置
每次调用,都会把用户的最新位置(userLocation参数)传进来
-(void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated;
地图的显示区域即将发生改变的时候调用
-(void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated;
地图的显示区域已经发生改变的时候调用
MKUserLocation
@property (nonatomic, copy) NSString *title;
显示在大头针上的标题
@property (nonatomic, copy) NSString *subtitle;
显示在大头针上的子标题
@property (readonly, nonatomic) CLLocation *location;
地理位置信息(大头针钉在什么地方?)
添加大头针
添加一个大头针
-(void)addAnnotation:(id )annotation;
添加多个大头针
-(void)addAnnotations:(NSArray *)annotations;
@interface TestAnnotation : NSObject <MKAnnotation>
@property (nonatomic, assign) CLLocationCoordinate2D coordinate;
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *subtitle;
复制代码
自定义大头针
设置MKMapView代理
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id )annotation;
根据传进来的(id )annotation参数创建并返回对应的大头针控件
注意:如果返回nil,显示出来的大头针就采取系统的默认样式
标识用户位置的蓝色发光圆点,它也是一个大头针,当显示这个大头针时,也会调用代理方法
因此,需要在代理方法中分清楚(id )annotation参数代表自定义的大头针还是蓝色发光圆点
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
// 判断annotation的类型
if (![annotation isKindOfClass:[TestAnnotation class]]) return nil
// 创建MKAnnotationView
static NSString *ID = @"tuangou"
MKAnnotationView *annoView = [mapView dequeueReusableAnnotationViewWithIdentifier:ID]
if (annoView == nil) {
annoView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:ID]
annoView.canShowCallout = YES
复制代码
MKAnnotationView
地图上的大头针控件是MKAnnotationView
@property (nonatomic, strong) id annotation;
大头针模型
@property (nonatomic, strong) UIImage *image;
显示的图片
@property (nonatomic) BOOL canShowCallout;
是否显示标注
@property (nonatomic) CGPoint calloutOffset;
标注的偏移量
@property (strong, nonatomic) UIView *rightCalloutAccessoryView;
标注右边显示什么控件
@property (strong, nonatomic) UIView *leftCalloutAccessoryView;
标注左边显示什么控件
@property (nonatomic, strong) UIView *detailCalloutAccessoryView
标注下面显示什么控件(iOS9.0)
MKPinAnnotationView比MKAnnotationView多了2个属性
@property (nonatomic) MKPinAnnotationColor pinColor;
大头针颜色
@property (nonatomic) BOOL animatesDrop;
大头针第一次显示时是否从天而降
MKMapItem调用系统APP进行导航
- (void)beginNavWithBeginPlacemark:(CLPlacemark *)beginPlacemark andEndPlacemark:(CLPlacemark *)endPlacemark
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 openMapsWithItems:@[item1, item2] launchOptions:launchDic];
复制代码
MKMapCamera地图街景
// 创建视角中心坐标
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地图截图
MKMapSnapshotOptions *options = [[MKMapSnapshotOptions alloc] init];
options.region = self.mapView.region;
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];
复制代码
原文地址:iOS开发-地图开发(CoreLocation和MapKit))