ios学习笔记之地图(上)

一 前言

ios8.0之后与ios8.0之前,对于CoreLocation的使用,还是有很大区别的。本文介绍下CLLocationManager类的基本使用、如何做简单的区域监听以及一个指南针小案例。

二 CLLocationManager类的基本使用及ios8.0与ios9.0的对比

首先要导入头文件
"#import "

需要获取用户位置信息时,要创建CLLocationManager位置管理者对象。

创建一个位置管理者

@property (nonatomic, strong) CLLocationManager *lm;

现在先懒加载下lm对象

#pragma mark - 懒加载
- (CLLocationManager *)lm{
    if (!_lm) {
        _lm = [[CLLocationManager alloc] init];
        _lm.delegate = self; // 设置代理
//        每隔多少米定位一次,如果不设置该值就会频繁调用代理方法"didUpdateLocations"方法
        _lm.distanceFilter = 100;
        
// desiredAccuracy 属性的取值,查看头文件,搜索CLLocationAccuracy,可以找到如下内容
//  extern const CLLocationAccuracy kCLLocationAccuracyBestForNavigation // 最适合导航
//  extern const CLLocationAccuracy kCLLocationAccuracyBest; //最好的
//  extern const CLLocationAccuracy kCLLocationAccuracyNearestTenMeters;//10米
//  extern const CLLocationAccuracy kCLLocationAccuracyHundredMeters;//100米
//  extern const CLLocationAccuracy kCLLocationAccuracyKilometer;//1000米
//  extern const CLLocationAccuracy kCLLocationAccuracyThreeKilometers;//300米
        
        
//        ios8.0之后的定位适配*********************************
        if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
            //        精确度越高,越耗电,定位时间越长
            _lm.desiredAccuracy = kCLLocationAccuracyBest;
            //        前台定位授权,默认情况下,不可以在后台获取位置,勾选后台模式location update
            [_lm requestWhenInUseAuthorization];
            //        前后台定位授权(请求永久授权,在Plist里添加key:NSLocationAlwaysUsageDescription)
//            [_lm requestAlwaysAuthorization];
        }

//        或者先判断_lm对象是否能够响应requestAlwaysAuthorization方法,能响应就执行,这样就不需要知道该方法是作用于8.0之后的
//        if ([_lm respondsToSelector:@selector(requestAlwaysAuthorization)]) {
//            [_lm requestAlwaysAuthorization];
//        }
        
    }
    return _lm;
}

在ios9.0后,又多了判断是否可以在后台更新位置allowsBackgroundLocationUpdates
那么我们的适配又要多一个判断

- (CLLocationManager *)lm{
    if (!_lm) {
        _lm = [[CLLocationManager alloc] init];
        _lm.delegate = self;
        _lm.distanceFilter = 100;
        
//        8.0定位适配*********************************
        if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
            _lm.desiredAccuracy = kCLLocationAccuracyBest;
            //        前台定位授权,默认情况下,不可以在后台获取位置,要勾选后台模式location update
           [_lm requestWhenInUseAuthorization];
            
        }

        //            ios9.0之后,期望进入后台也能定位,多了这个allowsBackgroundLocationUpdates属性需配置,进入后台运行时,顶部有蓝条,与8.0版本一样
//        所以遇到了版本是9.0的用户,又要适配下
        if ([[UIDevice currentDevice].systemVersion floatValue] >= 9.0) {
//            command点击该属性进入文件查看,会发现警告你使用该属性时,一定要勾选后台模式location updates
            _lm.allowsBackgroundLocationUpdates = YES;
        }
    }
    return _lm;
}

当位置改变后,通过代理来告知我们。

// 点击屏幕,开始测试
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    
    [self.lm startUpdatingLocation];
    
//    [self.lm requestLocation];// 这个方法现在已经不常用了,了解即可,该方法头文件使用说明说,其不能与startUpdatingLocation or  allowDeferredLocationUpdates同时用
    
    
//    测试下distanceFromLocation方法,纬度上相差1度,地理上大概相差111km
//    CLLocation *lo1 = [[CLLocation alloc] initWithLatitude:21.77 longitude:22.99];
//    CLLocation *lo2 = [[CLLocation alloc] initWithLatitude:22.77 longitude:22.99];
//    CLLocationDistance distance = [lo1 distanceFromLocation:lo2];
//    NSLog(@"distance = %f",distance);
//    结果:2017-03-06 17:03:47.123 地图ios8.0+[90641:12476302] distance = 110733.934092   (大概是111km)
    
}

#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
    NSLog(@"定位到了");
    
//    拿到数组里最新的数据lastObject
    
    /**
     *  CLLocation详解
     *  coordinate :坐标,经纬度
     *  altitude:海拔
     *  course:航向
     *  speed:速度
     *  latitude:纬度
     *  longtitude:经度
     */
    CLLocation *location = [locations lastObject];
    
    /**
     * 场景演练:打印当前用户的行走方向,偏离角度以及对应的行走距离,
     * 例如:”北偏东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) {
        angleStr = [angleStr substringToIndex:1];
        
        angleStr = [NSString stringWithFormat:@"正%@",angleStr];
    }
    
    
//    3 移动多少米
    double distance = 0;
    if (_oldL) {
        distance = [location distanceFromLocation:_oldL];
    }
    
    _oldL = location;
//    4 拼串打印
    NSString *noticeStr = [NSString stringWithFormat:@"%@%zd度方向,移动了%f米",angleStr,angle,distance];
    NSLog(@"%@",noticeStr);
}


/**
 授权状态发生改变时调用

 @param manager 位置管理者
 @param status 状态
 */
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status{
//    CLAuthorizationStatus是枚举类型,我们可以依照源文件,来解析下当前的用户位置状态
    NSLog(@"status = %d",status);
    
    
}

/**
 定位失败(配合requestLocation方法)

 @param manager <#manager description#>
 @param error <#error description#>
 */
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
    
}

打开模拟器,选择你需要的模拟位置变化状态。

ios学习笔记之地图(上)_第1张图片
三 区域监听
#import "ViewController.h"
#import 
@interface ViewController ()
@property (nonatomic, strong) CLLocationManager *lM;
@end

@implementation ViewController
// 懒加载
- (CLLocationManager *)lM{
    if (!_lM) {
        _lM = [[CLLocationManager alloc] init];
        _lM.delegate = self;
        
        if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
            [_lM requestAlwaysAuthorization];
        }
        
    }
    return _lM;
}


- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    
//    给定区域region,标识为@"qingyun"
    CLLocationCoordinate2D center = {21.33,123.99};
    CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:center radius:1000 identifier:@"qingyun"]; //identifier是用来标识具体是哪个区域的
//    开始监听区域region
    [self.lM startMonitoringForRegion:region];
    
    //    给定区域regin2,标识为@"qingyun2"
    CLLocationCoordinate2D center2 = {33.33,123.99};
    CLCircularRegion *regin2 = [[CLCircularRegion alloc] initWithCenter:center2 radius:1000 identifier:@"qingyun2"];
    //    开始监听区域region2
    [self.lM startMonitoringForRegion:regin2];
    
//    请求指定区域的状态(状态包括:1 无法监听到 2 在该区域内 3 在该区域外)
    [self.lM requestStateForRegion:region];
    
}

#pragma mark - CLLocationManagerDelegate
//进入区域,只有当你动态进入时,才会调用
- (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{
    
    NSString *str = nil;
//    CLRegionStateUnknown,
//    CLRegionStateInside,
//    CLRegionStateOutside
    switch (state) {
        case CLRegionStateUnknown:
            str = @"CLRegionStateUnknown";
            break;
         case CLRegionStateInside:
            str = @"CLRegionStateInside";
            break;
        case CLRegionStateOutside:
            str = @"CLRegionStateOutside";
            break;
        default:
            str = @"我不知道";
            break;
    }
    
    NSLog(@"state = %@  region.identifier = %@",str,region.identifier);
    
}

//运行之后会打印:
//[94660:13100043] state = CLRegionStateInside  region.identifier = qingyun

//将模拟器经纬度从:{21.33,123.99}改成:{22.33,123.99}后会有如下打印:
//2017-03-10 11:13:48.246 CoreLocation-区域监听[94660:13100043] 离开区域,qingyun
//2017-03-10 11:13:48.247 CoreLocation-区域监听[94660:13100043] state = CLRegionStateOutside  region.identifier = qingyun



@end

模拟器Debug->Location->CustomLocation 可以修改下当前位置

四 指南针的基本实现

首先选择一个指南针图片到你的项目里

ios学习笔记之地图(上)_第2张图片

单纯的做指南针(指向的方向其实是磁极的南和北)是不需要授权的,因为获取用户方向不牵扯到用户隐私

#import "ViewController.h"
#import 
@interface ViewController ()
@property (nonatomic, strong) CLLocationManager *lm;
@property (weak, nonatomic) IBOutlet UIImageView *compass;

@end

@implementation ViewController
#pragma mark - 懒加载

- (CLLocationManager *)lm{
    if (!_lm) {
        _lm = [[CLLocationManager alloc] init];
        _lm.delegate = self;
//        每隔多少度更新一次
        _lm.headingFilter = 2;    
    }
    return _lm;
}

- (void)viewDidLoad {
    [super viewDidLoad];
//    开始更新设备朝向
    [self.lm startUpdatingHeading];
}


#pragma mark - CLLocationManagerDelegate

/**
 获取到手机朝向时调用

 @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.compass.transform = CGAffineTransformMakeRotation(-angleR);
    }];

    
}


@end

你可能感兴趣的