iOS关于地图定位基础(二)[通俗易懂]

iOS关于地图定位基础(二)[通俗易懂]在前一篇文章 iOS关于地图定位基础(一) 中我们主要总结了 iOS里面利用原生 CoreLocation 框架实现基本定位功能和一些注意点,侧重点主要是iOS8+之后的定位授权与授权状态的使用。接下来本篇文章主要是讲解如何利用 CoreLocation 框架实现地理定位的具体实现。(PS:下文涉及我自定义的指南针Demo请去我的GitHub仓库查看源码https://github.com/IML

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

  在前一篇文章 iOS关于地图定位基础(一) 中我们主要总结了 iOS 里面利用原生 CoreLocation 框架实现基本定位功能和一些注意点,侧重点主要是iOS8+之后的定位授权与授权状态的使用。接下来本篇文章主要是讲解如何利用 CoreLocation 框架实现地理定位、区域监听、地理编码的具体实现。(PS:下文涉及我自定义的指南针Demo请去我的GitHub仓库查看源码https://github.com/IMLoser/HWCompass,谢谢大家支持。)

  一、定位实现&监听方向)那么我们先来看看这个代理方法:  

// 通过位置管理者一旦定位到位置,就会一直调用这个代理方法
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations;


  在这个方法中共有两个参数,一个是位置管理者,另一个就是保存有位置对象(CLLocation)的数组,这个数组中位置对象的存放顺序是按照时间排序的,那么最新的定位信息永远是数组最后一个元素。那么 CLLocation 对象又是什么呢?我们看看以下代码:

#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
    
    CLLocation * location = [locations lastObject];
    
    /*
     
     CLLocation 位置对象的重要属性:
     
     coordinate 定位到的经纬度坐标
     altitude 海拔
     horizontalAccuracy 水平精确度
     verticalAccuracy 垂直精确度
     course 航向(取值0 ~ 359.9)
     speed 速度
     
     */
    
}


  光看干巴巴的属性来学习始终不够形象,下面我们来看个小案例 : 显示用户每次行走的方向和角度以及针对于上一次定位行走的距离,如 :  北偏东 30度 移动了12米。代码如下 :

{
    // 记录上一次位置
    CLLocation *_oldLocation;
}

#pragma mark - CLLocationManagerDelegate- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {        CLLocation * location = [locations lastObject];    NSString * locationInfo = nil;    NSInteger direction = (NSInteger)location.course / 90;        // 获取方向    switch (direction) {        case 0:            locationInfo = @"北偏东";            break;                    case 1:            locationInfo = @"东偏南";            break;                    case 2:            locationInfo = @"南偏西";            break;                    case 3:            locationInfo = @"西偏北";            break;                    default:            break;    }            // 获取角度    NSInteger angle = (NSInteger)location.course % 90;    if (!angle) {                locationInfo = [NSString stringWithFormat:@"正%@", [locationInfo substringToIndex:1]];            } else {        locationInfo = [locationInfo stringByAppendingString:[NSString stringWithFormat:@"%zd度", angle]];    }            // 获取移动的距离    NSInteger distance = 0;    if (_oldLocation) {        distance = [location distanceFromLocation:_oldLocation];    }    _oldLocation = location;            // 拼接打印    locationInfo = [locationInfo stringByAppendingString:[NSString stringWithFormat:@"移动了%zd米", distance]];    NSLog(@"%@", locationInfo);}

iOS关于地图定位基础(二)[通俗易懂]

  我们不仅可以获取用户的位置信息,也可以获取用户的方向信息。这里可以简单的制作一个指南针控件,废话不多讲,我们先来看看效果图:

iOS关于地图定位基础(二)[通俗易懂]

  必须提一下的是,想要实现这个效果模拟器就有些力不从心,所以在运行效果Demo的时候我选择了真机。。。核心代码如下:

#import <UIKit/UIKit.h>

@interface HWCompass : UIView

// 获得指南针
+ (instancetype)getCompass;

// 开始获取方向
- (void)startUpdateHeading;

@end
#import "HWCompass.h"
#import <CoreLocation/CoreLocation.h>

@interface HWCompass () <CLLocationManagerDelegate>

/** 指南针视图 */
@property (nonatomic, weak) UIImageView * compassView;

/** 定位管理者 */
@property (strong, nonatomic) CLLocationManager * clManager;

@end

@implementation HWCompass

#pragma mark - lazy
- (CLLocationManager *)clManager
{
    if (!_clManager) {
        _clManager = [[CLLocationManager alloc] init];
        _clManager.delegate = self;
        
        if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
            [_clManager requestAlwaysAuthorization];
        }
        
        if ([[UIDevice currentDevice].systemVersion floatValue] >= 9.0) {
            [_clManager allowsBackgroundLocationUpdates];
        }
        
    }
    return _clManager;
}

+ (instancetype)getCompass
{
    HWCompass * compass = [[HWCompass alloc] init];
    compass.backgroundColor = [UIColor clearColor];
    return compass;
}

- (void)startUpdateHeading
{
    [self.clManager startUpdatingHeading];
}

- (instancetype)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame]) {
        [self initailSetting];
    }
    return self;
}

- (void)awakeFromNib {
    [super awakeFromNib];
    
    [self initailSetting];
}

- (void)initailSetting
{
    UIImageView * compassView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"compass"]];
    _compassView = compassView;
    [self addSubview:compassView];
    
}

- (void)layoutSubviews
{
    [super layoutSubviews];
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
        // 长宽相等
        CGRect tmpFrame = self.frame;
        tmpFrame.size.height = tmpFrame.size.width;
        self.frame = tmpFrame;
        
        // 设置指南针视图
        _compassView.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
        
    });
}

#pragma mark - CLLocationManagerDelegate

- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading {

    [UIView animateWithDuration:0.1 animations:^{
        _compassView.transform = CGAffineTransformMakeRotation(M_PI * 2 - M_PI / 180 * newHeading.magneticHeading);
    }];
}

@end

  以上这个是我自定义的指南针控件的代码,下面是控制器中的调用操作。。。

#import "ViewController.h"
#import "HWCompass.h"

@interface ViewController ()

/**
 *  指南针
 */
@property (nonatomic, weak) HWCompass * compass;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
   
    // 设置背景颜色
    self.view.backgroundColor = [UIColor blackColor];
    
    // 创建指南针控件
    HWCompass * compass = [HWCompass getCompass];
    _compass = compass;
    compass.frame = CGRectMake(0, 0, 200, 200);
    compass.center = CGPointMake(self.view.bounds.size.width * 0.5, self.view.bounds.size.height * 0.5);
    [self.view addSubview:compass];
    
}

// 点击启动指南针功能
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
    [_compass startUpdateHeading];
}

@end

  二、区域监听接下来我们来聊聊利用CoreLocation 框架实现简单的区域监听。这里需要补充的是在制作指南针的时候其实是没有必要申请用户授权的,因为获取方向不会涉及到用户隐私问题。但是用到区域监听功能时和定位的用户授权则是一样的。用到的核心类还是定位管理者CLLocationManager,懒加载创建、设置代理、授权都和定位功能实现是一样的;但是开启区域监听的方法、调用的代理确有些不同,具体代码实现如下 :

#import "ViewController.h" #import <CoreLocation/CoreLocation.h> @interface ViewController () <CLLocationManagerDelegate> /** 定位管理者 */ @property (strong, nonatomic) CLLocationManager * clManager; @end @implementation ViewController - (CLLocationManager *)clManager { if (!_clManager) { _clManager = [[CLLocationManager alloc] init]; // 设置代理 _clManager.delegate = self; // 获取授权 if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) { // 获取前后台授权 [_clManager requestAlwaysAuthorization]; } } return _clManager; } // 点击屏幕开启区域监听 - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { // 要监听圆形区域A的中心点 CLLocationCoordinate2D centerA = CLLocationCoordinate2DMake(42.22, 121.11); // 设定监控的区域A CLCircularRegion * regionA = [[CLCircularRegion alloc] initWithCenter:centerA radius:1000 identifier:@"区域A"]; // 开始区域监听区域A [self.clManager startMonitoringForRegion:regionA]; // 要监听圆形区域B的中心点 CLLocationCoordinate2D centerB = CLLocationCoordinate2DMake(22.22, 80.11); // 设定监控的区域B CLCircularRegion * regionB = [[CLCircularRegion alloc] initWithCenter:centerB radius:1000 identifier:@"区域B"]; // 开始区域监听区域B [self.clManager startMonitoringForRegion:regionB]; } #pragma mark - CLLocationManagerDelegate // 已经进入到监控的区域 - (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region { NSLog(@"进入区域%@", region.identifier); } // 已经离开监听的区域 - (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region { NSLog(@"离开区域%@", region.identifier); } @end

  当我们视图更改模拟器坐标时,对应代理方法会针对是否进入或离开某个区域进行调用,具体打印如下 :

iOS关于地图定位基础(二)[通俗易懂]

  这里还有一个知识点的补充,我们还可以监听是否进入区域的状态,调用CLLocationManager 的实例方法 :

 // 开始区域监听区域A // [self.clManager startMonitoringForRegion:regionA]; // 监听是否进入指定区域的状态(以上开启区域监听方法不调用亦可) [self.clManager requestStateForRegion:regionA];

  实现对应的监听区域状态代理方法 :

- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region; - (void)locationManager:(CLLocationManager *)manager     didEnterRegion:(CLRegion *)region; - (void)locationManager:(CLLocationManager *)manager     didExitRegion:(CLRegion *)region; 

  具体代码实现如下 :

#import "ViewController.h" #import <CoreLocation/CoreLocation.h> @interface ViewController () <CLLocationManagerDelegate> /** 定位管理者 */ @property (strong, nonatomic) CLLocationManager * clManager; @end @implementation ViewController - (CLLocationManager *)clManager { if (!_clManager) { _clManager = [[CLLocationManager alloc] init]; // 设置代理 _clManager.delegate = self; // 获取授权 if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) { // 获取前后台授权 [_clManager requestAlwaysAuthorization]; } } return _clManager; } // 点击屏幕开启区域监听 - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { // 要监听圆形区域A的中心点 CLLocationCoordinate2D centerA = CLLocationCoordinate2DMake(42.22, 121.11); // 设定监控的区域A CLCircularRegion * regionA = [[CLCircularRegion alloc] initWithCenter:centerA radius:1000 identifier:@"区域A"]; // 开始区域监听区域A // [self.clManager startMonitoringForRegion:regionA]; // 监听是否进入指定区域的状态(以上开启区域监听方法不调用亦可) [self.clManager requestStateForRegion:regionA]; } #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 { switch (state) { case 0: NSLog(@"未知的state"); break; case 1: NSLog(@"进入区域state"); break; case 2: NSLog(@"离开区域state"); break; default: break; } } @end

iOS关于地图定位基础(二)[通俗易懂]

三、地理编码&反编码)最后我们聊聊地理编码和反编码,用到的核心类是CoreLocation 框架中的CLGeocoder(编码器),所谓地理编码简单点讲就是把地名转换为坐标(经纬度),那相反的把地理左边转换为地名等等就叫做地理反编码了。此外还要接触一个新类CLPlacemark。我们先来看下案例的效果图 :

iOS关于地图定位基础(二)[通俗易懂]

 具体代码如下 :

#import "ViewController.h" #import <CoreLocation/CoreLocation.h> @interface ViewController () /** 地理编码器 */ @property (strong, nonatomic) CLGeocoder * geocoder; @property (weak, nonatomic) IBOutlet UITextView *clInfoName; @property (weak, nonatomic) IBOutlet UITextField *clLatitude; @property (weak, nonatomic) IBOutlet UITextField *clLongitude; @end @implementation ViewController #pragma mark - lazy - (CLGeocoder *)geocoder { if (!_geocoder) { _geocoder = [[CLGeocoder alloc] init]; } return _geocoder; } // 地理编码 - (IBAction)geoClick { _clLatitude.text = @"查询中..."; _clLongitude.text = @"查询中..."; [self.geocoder geocodeAddressString:_clInfoName.text completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) { if (error) { _clLatitude.text = @"未查到"; _clLongitude.text = @"未查到"; return; } CLPlacemark * firstPlacemark = placemarks.firstObject; _clLatitude.text = [NSString stringWithFormat:@"%.2f", firstPlacemark.location.coordinate.latitude]; _clLongitude.text = [NSString stringWithFormat:@"%.2f", firstPlacemark.location.coordinate.longitude]; }]; } // 地理反编码 - (IBAction)reverseGeoClick { _clInfoName.text = @"查询中..."; CLLocation * location = [[CLLocation alloc] initWithLatitude:[_clLatitude.text doubleValue] longitude:[_clLongitude.text doubleValue]]; [self.geocoder reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) { if (error) { _clInfoName.text = @"未查询到"; return; } CLPlacemark * firstPlacemark = placemarks.firstObject; _clInfoName.text = firstPlacemark.locality; }]; } - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [self.view resignFirstResponder]; _clInfoName.text = @""; _clLatitude.text = @""; _clLongitude.text = @""; } @end

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/158793.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • UCOSII系统时间管理[通俗易懂]

    UCOSII系统时间管理[通俗易懂]一,UCOSII的定时中断绝大多数的内核要求提供定时中断,以实现延时与超时控制等功能。这个定时中断叫做时钟节拍。时钟的中断子程序ISR和时钟节拍函数OSTimeTick()该函数通知UCOSII,发生了时钟节拍中断。二,UCOSII系统时钟函数1,任务延时函数,OSTimeDly(INT16Uticks)实现申请该服务的任务可以延时一段时间这个系统服务的函数叫做OSTimeDly(),这段时间的长短是用时钟节拍的数目来确定的。调用该函数会使µC/OS-Ⅱ进行一次任务调度,并且执行下一个优

  • 【OpenCV】双线性插值法

    【OpenCV】双线性插值法双线性插值法定义:又称双线性内插。在数学上,双线性插值是有两个变量的插值函数的线性插值扩展,其核心思想是在两个方向上分别进行一次线性插值。对于一个目的像素,设置坐标通过反向变换得到的浮点坐标为(i+u,j+v)(其中i、j均为浮点坐标的整数部分,u、v为浮点坐标的小数部分,是取值[0,1)区间的浮点数),则这个像素得值f(i+u,j+v)可由原图像中坐标为(i,j)、(…

  • 什么是跨域?跨域解决方法

    什么是跨域?跨域解决方法一、为什么会出现跨域问题出于浏览器的同源策略限制。同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具有相同的协…

  • android 安装p12证书,如何在Android中使用p12证书(客户端证书)

    android 安装p12证书,如何在Android中使用p12证书(客户端证书)我试图在android中使用客户端证书。我得到了一个.p12文件,我想用它来对服务器进行身份验证。如何在Android中使用p12证书(客户端证书)我正在使用portecle将.p12文件转换为.bks文件,但我似乎没有得到它的工作。下面的代码:packagecom.pa1406.SECURE;importjava.io.InputStream;importjava.security.Ke…

  • 直接学 Vue 3 吧 —— 对话 Vue.js 作者尤雨溪[通俗易懂]

    直接学 Vue 3 吧 —— 对话 Vue.js 作者尤雨溪[通俗易懂]《程序员》于2000年创刊,其理念为技术改变世界,创新驱动中国。2021年,《程序员》2.0全新起航,首期以「开发者的黄金十年」为主题,以音视频、图文专栏等丰富的多媒体形式为载体,立足当下,放眼未来,为读者带来全方位的技术和产业解读。本文为《程序员》2.0第一期内容,在UNIX开发者BrianW.Kernighan之后,我们采访到Vue.js的作者尤雨溪,与其共谈精彩程序人生、共论顶级开源项目的成功之道。从复杂的jQuery插件化开发到模块化及组件化,现代前端技术在迭代.

  • Apache的URL地址重写(RewriteCond与RewriteRule)

    Apache的URL地址重写(RewriteCond与RewriteRule)Apache的URL地址重写http://hi.baidu.com/sonan/blog/item/c408963d89468208bba16716.html第一种方法:Apache环境中如果要将URL地址重写,正则表达式是最基本的要求,但对于一般的URL地址来说,基本的匹配就能实现我们大部分要求,因此除非是非常特殊的URL地址,但这不是我要讨论的范围,简单几招学会Apache中URL地

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号