CoreLocation框架ios
MapKit框架git
CoreLocation:用于地理定位,地理编码区域监听等(着重功能实现)
MapKit:用于地图展现,例如大头针,路线,覆盖层展现等(着重界面展现)
复制代码
CoreLocation框架中使用CLLocationManager对象来作用户定位 建立(初始化)api
CLLocationManager *lM = [[CLLocationManager alloc] init];
复制代码
每隔多少米定位一次数组
@property(assign, nonatomic) CLLocationDistance distanceFilter;
复制代码
定位精确度(越精确就越耗电)bash
@property(assign, nonatomic) CLLocationAccuracy desiredAccuracy;
复制代码
朝向改变时,每隔多少度调用一次app
@property(assign, nonatomic) CLLocationDegrees headingFilter
复制代码
每隔多米定位一次框架
_lM.distanceFilter = 100;
/**
kCLLocationAccuracyBestForNavigation // 最适合导航
kCLLocationAccuracyBest; // 最好的
kCLLocationAccuracyNearestTenMeters; // 10m
kCLLocationAccuracyHundredMeters; // 100m
kCLLocationAccuracyKilometer; // 1000m
kCLLocationAccuracyThreeKilometers; // 3000m
*/
// 精确度越高, 越耗电, 定位时间越长
_lM.desiredAccuracy = kCLLocationAccuracyBest;
复制代码
- (void)startUpdatingLocation;
复制代码
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations;
复制代码
locations参数里面装着CLLocation对象ide
- (void) stopUpdatingLocation;
复制代码
判判定位功能是否可用(为了严谨起见,最好在使用定位功能前进行判断)ui
+ (BOOL)locationServicesEnabled;
复制代码
监听设备朝向编码
-(void)startUpdatingHeading(如试例代码中的指南针的实现)
复制代码
区域监听(监听进出某个区域)
-(void)requestStateForRegion:region;
复制代码
//使用位置管理者,开始更新用户位置
// 默认只能在前台获取用户位置,
// 勾选后台模式 location updates
[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(@"定位到了");
// 拿到位置,作一些业务逻辑操做
// 中止更新
// [manager stopUpdatingLocation];
}
复制代码
/**
* 受权状态发生改变时调用
*
* @param manager 位置管理者
* @param status 状态
*/
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
switch (status) {
// 用户还未决定
case kCLAuthorizationStatusNotDetermined:
{
NSLog(@"用户还未决定");
break;
}
// 问受限
case kCLAuthorizationStatusRestricted:
{
NSLog(@"访问受限");
break;
}
// 定位关闭时和对此APP受权为never时调用
case kCLAuthorizationStatusDenied:
{
// 定位是否可用(是否支持定位或者定位是否开启)
if([CLLocationManager locationServicesEnabled])
{
NSLog(@"定位开启,但被拒");
}else
{
NSLog(@"定位关闭,不可用");
}
// NSLog(@"被拒");
break;
}
// 获取先后台定位受权
case kCLAuthorizationStatusAuthorizedAlways:
// case kCLAuthorizationStatusAuthorized: // 失效,不建议使用
{
NSLog(@"获取先后台定位受权");
break;
}
// 得到前台定位受权
case kCLAuthorizationStatusAuthorizedWhenInUse:
{
NSLog(@"得到前台定位受权");
break;
}
default:
break;
}
}
复制代码
/**
* 简易指南针的实现
* 手机朝向改变时调用
*
* @param manager 位置管理者
* @param newHeading 朝向对象
*/
-(void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
/**
* CLHeading
* magneticHeading : 磁北角度
* trueHeading : 真北角度
*/
NSLog(@"%f", newHeading.magneticHeading);
CGFloat angle = newHeading.magneticHeading;
// 把角度转弧度
CGFloat angleR = angle / 180.0 * M_PI;
// 旋转图片(指南针图片)
[UIView animateWithDuration:0.25 animations:^{
self.compassView.transform = CGAffineTransformMakeRotation(-angleR);
}];
}
复制代码
//区域监听的代理方法
// 进入区域
-(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
{
//state的值
//CLRegionStateUnknown,
//CLRegionStateInside,
//CLRegionStateOutside
NSLog(@"%zd", state);
}
复制代码
CLLocation用来表示某个位置的地理信息,好比经纬度,海拔等等
经常使用属性
@property(readonly, nonatomic) CLLocationCoordinate2D coordinate;
复制代码
@property(readonly, nonatomic) CLLocationDistance altitude;
复制代码
@property(readonly, nonatomic) CLLocationDirection course;
复制代码
@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);
}
复制代码
从ios8.0开始,苹果进一步增强了对用户隐私的保护。
当app想访问用户的隐私时,系统再也不自动弹出一个对话框让用户受权.
(1)调用ios8.0的api。主动请求用户受权
(2)务必在info.plist文件中配置对应的键值, 不然以上请求受权的方法不生效
ios9.0若是当前处于前台受权状态,默认是不能够后台获取用户位置。但能够设置如下属性为YES,就能够继续在后台获取位置,可是在屏幕上方会出现蓝条
ios9.0能够单次请求用户位置
使用CLGeocoder能够完成“地理编码”和“反地理编码”
对应方法
-(void)geocodeAddressString:(NSString *)addressString completionHandler:(CLGeocodeCompletionHandler)completionHandler;
复制代码
-(void)reverseGeocodeLocation:(CLLocation *)location completionHandler:(CLGeocodeCompletionHandler)completionHandler;
复制代码
CLGeocodeCompletionHandler:反地理编码完成时,就会调用CLGeocodeCompletionHandler
typedef void (^CLGeocodeCompletionHandler)(NSArray *placemarks, NSError *error);
// 地理编码
- (IBAction)geoCoder {
//当传入的值为0时直接返回
if ([self.addressDetailTV.text length] == 0) {
return;
}
// 地理编码方案一:直接根据地址进行地理编码(返回结果可能有多个,由于一个地点有重名)
[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对象
CLLocation *location = [[CLLocation alloc] initWithLatitude:[self.latitudeTF.text doubleValue] longitude:[self.longtitudeTF.text doubleValue]];
// 根据CLLocation对象进行反地理编码
[self.geoC reverseGeocodeLocation:location 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];
}];
}
复制代码
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;
复制代码
经常使用属性
地图配型:mapType
操做项
显示项
跟踪显示用户的位置(ios8-地图不会自动滚到用户所在的位置,ios8+地图会自动放大到合适比例,并显示出用户位置)
设置地图显示的区域和位置
设置地图的中心点位置
设置地图的显示区域
typedef struct {
CLLocationCoordinate2D center; // 区域的中心点位置
MKCoordinateSpan span; // 区域的跨度
} MKCoordinateRegion;
复制代码
typedef struct {
CLLocationDegrees latitudeDelta; // 纬度跨度
CLLocationDegrees longitudeDelta; // 经度跨度
} MKCoordinateSpan;
复制代码
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation;
-(void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated;
-(void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated;
添加大头针
移除大头针
#import <MapKit/MapKit.h>
@interface TestAnnotation : NSObject <MKAnnotation>
/** 坐标位置 */
@property (nonatomic, assign) CLLocationCoordinate2D coordinate;
/** 标题 */
@property (nonatomic, copy) NSString *title;
/** 子标题 */
@property (nonatomic, copy) NSString *subtitle;
@end
复制代码
设置MKMapView代理
- (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
属性
MKPinAnnotationView是MKAnnotationView的子类
MKPinAnnotationView比MKAnnotationView多了2个属性
// 根据两个地标对象进行调用系统导航
- (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];
}
复制代码
// 建立视角中心坐标
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;
复制代码
// 截图附加选项
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];
}
}];
复制代码