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

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

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

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 程序解码错误:Accept-Encoding“: “gzip, deflate, br[通俗易懂]

    程序解码错误:Accept-Encoding“: “gzip, deflate, br[通俗易懂]请求头设置”Accept-Encoding”:”gzip,deflate,br”返回的数据是乱码,无论设置utf-8、gbk、gb2312都无法解码一个奇怪的现象是本地测试可以正常解码,代码在服务器上运行就无法解码,最终将该请求头去除就正常了。…

    2022年7月15日
    50
  • tensorflow2.0手写数字识别(tensorflow手写体识别)

    本节笔记作为Tensorflow的HelloWorld,用MNIST手写数字识别来探索Tensorflow。笔记的内容来自Tensorflow中文社区和黄文坚的《Tensorflow实战》,只作为自己复习总结。

    2022年4月17日
    133
  • python跳出循环重新开始_python怎么跳出循环

    python跳出循环重新开始_python怎么跳出循环本文主要讲下python中的break语句用法,常用在满足某个条件,需要立刻退出当前循环时(跳出循环),break语句可以用在for循环和while循环语句中。简单的说,break语句是会立即退出循环,在其后边的循环代码不会被执行。break语句的用法>>>x=1>>>whileTrue:>>>x+=1>>>…

    2022年6月3日
    117
  • 2019的10个最佳WordPress画廊插件

    2019的10个最佳WordPress画廊插件在视觉文化时代,如果您的网站包含图片,则它会获得更多的观看次数。研究表明,如果带有照片或视频,您的内容将获得更好的好评。这很有意义,因为大多数人都以视觉为导向,而我们的大脑在视觉上比在文本中更快地处理和理解事物。不仅如此,大多数人都可以在带有图像的情况下更好地处理和理解文本。这就是为什么显示网站上的照片或视频会使内容的参与度提高70%以上的原因。这也是同样的原因,如果您包含图…

    2022年6月5日
    47
  • SpringBoot是什么?干嘛用的?(新手入门篇)

    SpringBoot是什么?干嘛用的?(新手入门篇)SpringBoot是干哈的介绍:springboot是由Pivotal团队提供的全新框架。spring的出现是为了解决企业级开发应用的复杂性,spring的通过注册bean的方式来管理类,但是随着业务的增加,使用xml配置bean的方式也显得相当繁琐,所以springboot就是为了解决spring配置繁琐的问题而诞生的,并且近几年来非常流行开启我的第一个HelloSpringBoot!开启方式根据https://start.spring.io网址创建一个springboot项目

    2022年10月26日
    0
  • R6010 -abort() has been called错误分析及其解决方法

    R6010 -abort() has been called错误分析及其解决方法

    2022年1月30日
    67

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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