热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

定位于地图小程序

导读:最近做了一个小程序模仿GPS,实现的基本功能有定位,地点查找,与导航等等,主要涉及到编码与反编码,(还有就是系统自己的)听着很麻烦,其实当自己理解了发现也不是那么难。废话也不多说

 导读:

       最近做了一个小程序模仿GPS,实现的基本功能有定位,地点查找,与导航等等,主要涉及到编码与反编码,(还有就是系统自己的)听着很麻烦,其实当自己理解了发现也不是那么难。废话也不多说。涉及到的函数根据代码来介绍。

我们先看看Main.storyboard,下图所示,结构非常简单,几个button,text,一个mapview。

介绍一下这个几个按钮的作用:

编码:就是把我们的输入的地点名字来获得它对应的经纬度以及详细信息。

反编码:就是把经纬度进行解析,获取这个经纬度对应的一些信息比如(城市,街道,乡。省)。

我的位置:定位到自己的位置。

路线(导航):根据自己的位置和搜索的地名来设计路线。

在我们写代码前我们还需要做几件事:

1.授权:打开工程中info.plist属性列表文件,添加2个键Privacy - Location Usage Description和Privacy - Location Always Usage Description。

2添加2个框架:如下图

在这里介绍一下这2框架,为什么我们要用到它:

CoreLocation框架:在IOS中,定位服务API主要使用的就是CoreLocation框架,在我们编制定位程序时,就要用到它的3个类。

1)CLLocationManager:他的作用在于可以为我们提供位置的一些信息(经纬度),还可以根据它来监控当时人所在的区域,前进方向。

2)CLLocationManagerDelegate:这是一个委托协议,我们在定位时需要用到它的一些方法。(下面在详细介绍)

3)CLLocation:封装了位置和高度信息。

MapKit框架:在IOS开发中,MKMapView类是开发地图应用的核心。使用Map Kit API就要导入MapKit框架。

-------这些都是小编我的自己感悟,并不代表全部,小编不可能把概念,功能全部写下来,如果想了解更加详细。请去网上查资料

目前介绍到这里,接下来进入代码环节

首先自定一个标注类:用来显示地址的信息:

MyAnnotation.h

 

#import 
#import

@interface MyAnnotation : NSObject
@property (nonatomic,readwrite)CLLocationCoordinate2D coordinate;
//地理坐标
@property(nonatomic,copy) NSString * street;//街道信息
@property(nonatomic,copy) NSString * city;//城市
@property(nonatomic,copy) NSString * state;//州,省,市;
@property(nonatomic,copy) NSString * zip; //邮编

MyAnnotation.m

#import "MyAnnotation.h"

@implementation MyAnnotation

-(NSString *)title{
return @"您的位置";
}
-(NSString *)subtitle{
NSMutableString
*ret=[NSMutableString new];
if (_state) {
[ret appendString:_state];
}
if (_city) {
[ret appendString:_city];
}
if (_city&&_state) {
[ret appendString:
@","];
}
if (_street&&(_city||_state||_city)) {
[ret appendString:
@"~"];
}
if (_street) {
[ret appendString:_street];
}
if (_zip ) {
[ret appendFormat:
@",%@",_zip];
}
return ret;
}
@end

 

ViewController.h

#import 
#import
#import
#import "MyAnnotation.h"

@interface ViewController : UIViewController
//地名
@property (weak, nonatomic) IBOutlet UITextField *txtKey;
//编码
- (IBAction)geocdeQuery:(id)sender;
//MkMapview 显示地图
@property (weak, nonatomic) IBOutlet MKMapView *mapview;
//我的位置
- (IBAction)reverseGeoccode:(id)sender;
//经度
@property (weak, nonatomic) IBOutlet UITextField *JingDuText;
//纬度
@property (weak, nonatomic) IBOutlet UITextField *WeiDuText;
//反编码
- (IBAction)reverseGeoccodeTwo:(id)sender;
//路线(导航)
- (IBAction)geocdeQueryTwo:(id)sender;
@end

 定义的几个控件与Main.storyboard一致的可以结合着看

#import 引入了CLLocation模块。
#import 我们添加MapKit框架

#import "MyAnnotation.h"我们自定一的一个类(标注)

让我们来看看viewcontroller.m的代码
@interface ViewController ()

@property(nonatomic,strong)CLLocationManager
*locationmanger;
@property(nonatomic,strong)CLLocation
*currlocation;
@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];
_mapview.mapType
=MKMapTypeStandard;//标注地图类型

// [_mapview setUserTrackingMode:MKUserTrackingModeFollow animated:YES];
// _mapview.userLocation.title=@"您的位置:";
// _mapview.userLocation.subtitle=@"xxxxxxxxxxx";

_mapview.
delegate=self;//


self.locationmanger
=[[CLLocationManager alloc]init];
//设置委托对象为自己
self.locationmanger.delegate=self;
//要求CLLocationManager对象的返回结果尽可能的精准
self.locationmanger.desiredAccuracy=kCLLocationAccuracyBest;
//设置距离筛选器distanceFilter,下面表示设备至少移动1000米,才通知委托更新
self.locationmanger.distanceFilter=1000.0f;

//使用中授权
[self.locationmanger requestWhenInUseAuthorization];
//永久授权
[self.locationmanger requestAlwaysAuthorization];

[self.locationmanger startUpdatingLocation];
}

CLLocationManagerDelegate申明遵守的协议。
地图显示的类型共有3种,他们是在枚举类型MKMapType中定义的(Standard)标注地图类型,(Satellite)卫星地图类型,(Hybrid)混合地图类型。
_mapview.delegate=self:将当前试图控制器负值给地图视图的delegate属性。这样地图视图会回掉viewcontroller,如果失败- (void)mapViewDidFailLoadingMap:(MKMapView *)mapView withError:(NSError *)error调用这个方法;
//回调viewcontroller失败:
- (void)mapViewDidFailLoadingMap:(MKMapView *)mapView withError:(NSError *)error{
NSLog(
@"error:%@",[error description]);
}

 

[self.locationmanger startUpdatingLocation];//开始定位

 开始定位后就要检查权限,是否允许定位服务:

//CLAuthorizationStatus枚举是定位的时候关于授权状态的一个枚举
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status{
NSLog(
@"status----->%d",status);
if (status == kCLAuthorizationStatusAuthorizedAlways) {
NSLog(
@"定位服务授权状态已经被用户允许在任何状态下获取位置信息。一直开启定位");
}
else if (status == kCLAuthorizationStatusAuthorizedWhenInUse){
NSLog(
@"定位服务授权状态仅被允许在使用应用程序的时候,当使用时开启定位");
}
else if (status == kCLAuthorizationStatusDenied){
NSLog(
@"定位服务授权状态已经被用户明确禁止,或者在设置里的定位服务中关闭");
}
else if (status == kCLAuthorizationStatusRestricted){
NSLog(
@"无法使用定位服务,该状态用户无法改变");
}
else if (status == kCLAuthorizationStatusNotDetermined){
NSLog(
@"用户尚未做出决定是否启用定位服务,用户从未选择过权限");
}


}

如果我们的定位服务已经开启,也设置了CLLocationManagerDelegate的属性delegate,就会回掉委托方法,如果定位失败:

-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
NSLog(
@"定位失败:%@",error );
}

定位成功:

//定位成功
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray
*)locations{
//取出数组的第一个信息
_currlocation=[locations firstObject];
//停止定位
[self.locationmanger stopUpdatingLocation];
//经纬度
NSString *lati=[NSString stringWithFormat:@"%3.5f",_currlocation.coordinate.latitude];
NSString
*lOngi=[NSString stringWithFormat:@"%3.5f",_currlocation.coordinate.longitude];
//打印出经纬度
NSLog(@"========%@---%@============",lati,longi);

//反编码
CLGeocoder*geocoder=[[CLGeocoder alloc]init];
[geocoder reverseGeocodeLocation:_currlocation completionHandler:
^(NSArray * _Nullable placemarks, NSError * _Nullable error) {
// if ([placemarks count]>0) {

CLPlacemark
*placemark=placemarks[0];
//地标字典,从地标集合中取出一个地标对象,循环便利就好
NSDictionary *addressDictiOnary=placemark.addressDictionary;
//从字典中取出街道。城市,省等信息
NSString *address=[addressDictionary objectForKey:(NSString*)NSTextCheckingStreetKey];
address
=address==nil ? @"" :address;
NSString
*state=[addressDictionary objectForKey:(NSString *)NSTextCheckingStateKey];
state
=state==nil ? @"" :state;
NSString
*city=[addressDictionary objectForKey:(NSString *)NSTextCheckingCityKey];
city
=city==nil ? @"" :city;

//把街道,城市,省 等一些信息组合起来
NSString *allname=[NSString stringWithFormat:@"%@%@%@",state,address,city];
//用MKCoordinateRegionMakeWithDistance建立一个结构体,调整地图位置和缩放比例
MKCoordinateRegion viewRegion=MKCoordinateRegionMakeWithDistance(placemark.location.coordinate, 10000, 10000);
[_mapview setRegion:viewRegion animated:YES];
//显示动画
//标注显示出来
MyAnnotation*annotation=[[MyAnnotation alloc]init];
annotation.state
=allname;
annotation.coordinate
=placemark.location.coordinate;
[_mapview addAnnotation:annotation];


}];

}

这串代码其实也不用介绍什么了小编在在注释里都写的非常清楚了。提几个注意的

在这串代码中我用的是反编码,是通过经纬度查找地点的信息,

reverseGeocodeLocation: completionHandler(反编码)

[_mapview addAnnotation:annotation];把annotation添加到地图视图上,这个方法一单被调用会回掉-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation

 

//在地图上添加标注时回调
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation{

MKPinAnnotationView
*annnotayiOnview=(MKPinAnnotationView *)[_mapview dequeueReusableAnnotationViewWithIdentifier:@"PIN_ANNOTATION"];
if (annnotayiOnview==nil) {
annnotayiOnview=[[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:@"PIN_ANNOTATION"];
}
//黑色
annnotayionview.pinTintColor=[UIColor blackColor];
//是否动画
annnotayionview.animatesDrop=YES;
//点击大头针会出现一个气泡,这个气泡回现实当前地址的信息
annnotayionview.canShowCallout=YES;

return annnotayionview;

}

红色部分代码的意思就是用dequeueReusableAnnotationViewWithIdentifier方法通过一个可重用的标识符“PIN_ANNOTATION”获得MKPinAnnotationView对象。在判断这个对象是否存在,如果不在(==nil)就重新创建一个

initWithAnnotation:reuseIdentifier(通过这个函数创建)

现在就来运行一下看看效果如何:


 好了目前实现一个基本的定位功能已经实现了

我们来实现我们的第一个button(编码) 的功能:通过输入的地名来查询

- (IBAction)geocdeQuery:(id)sender {
if (_txtKey.text==nil|| _txtKey.text.length==0) { //判断输入的地址是否符合规定
return;
}
// [self.locationmanger startUpdatingLocation];
CLGeocoder*geocoder=[[CLGeocoder alloc]init];// 声明GLGeocoder对象并初始化
//开始编码
[geocoder geocodeAddressString:_txtKey.text completionHandler:^(NSArray * _Nullable placemarks, NSError * _Nullable error) {
NSLog(
@"------->%lu",[placemarks count]);

if ([placemarks count]>0) {
[_mapview removeAnnotations:_mapview.annotations];
for (int i=0; i<[placemarks count]; i++) {
CLPlacemark
*placemark=placemarks[i];
//用MKCoordinateRegionMakeWithDistance建立一个结构体,调整地图位置和缩放比例
MKCoordinateRegion viewRegion=MKCoordinateRegionMakeWithDistance(placemark.location.coordinate, 10000, 10000);
[_mapview setRegion:viewRegion animated:YES];
//设置动画效果

MyAnnotation
*annotation=[[MyAnnotation alloc]init];
annotation.street
=placemark.thoroughfare;
annotation.city
=placemark.locality;
annotation.state
=placemark.administrativeArea;
annotation.zip
=placemark.postalCode;
annotation.coordinate
=placemark.location.coordinate;

[_mapview addAnnotation:annotation];
//把annotation添加到地图视图上,这个方法一单被调用会回掉-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation
//获取地标经纬度信息
CLLocationCoordinate2D coordinate=placemark.location.coordinate;
//从text中显示出来
self.JingDuText.text=[NSString stringWithFormat:@"%3.5f",coordinate.latitude];
self.WeiDuText.text
=[NSString stringWithFormat:@"%3.5f",coordinate.longitude];
}
}
}];
}

geocodeAddressString:completionHandler;方法进行地理信息编码查询,查询的结果placemarks是一个NSArray类型

在上面我们介绍了一下反编码,现在我来介绍一下编码

geocodeAddressDictionary:completionHandler: 通过指定一个地址信息字典对象参数进行查询

geocodeAddressString:completionHandler:通过指定一个地址信息字符串参数进行查询

geocodeAddressString:inRegion:completionHandler:通过制定地址信息字符串和查询范围进行查询

 [_mapview removeAnnotations:_mapview.annotations]:移除地图上的标记点,否则反复查询地图上的标记点会越来越多

 

第二个button(反编码)的功能

- (IBAction)reverseGeoccodeTwo:(id)sender {
//把经纬度提取出来
CLLocation *myLocal=[[CLLocation alloc]initWithLatitude:[self.JingDuText.text doubleValue] longitude:[self.WeiDuText.text doubleValue]];
CLGeocoder
*grocode=[[CLGeocoder alloc]init];

[grocode reverseGeocodeLocation:myLocal completionHandler:
^(NSArray * _Nullable placemarks, NSError * _Nullable error) {


CLPlacemark
*placemark=placemarks[0];

NSDictionary
*addressDictiOnary=placemark.addressDictionary;

NSString
*address=[addressDictionary objectForKey:(NSString*)NSTextCheckingStreetKey];
address
=address==nil ? @"" :address;
NSString
*state=[addressDictionary objectForKey:(NSString *)NSTextCheckingStateKey];
state
=state==nil ? @"" :state;
NSString
*city=[addressDictionary objectForKey:(NSString *)NSTextCheckingCityKey];
city
=city==nil ? @"" :city;


NSString
*allname=[NSString stringWithFormat:@"%@%@%@",state,address,city];
self.txtKey.text
=city;
MKCoordinateRegion viewRegion
=MKCoordinateRegionMakeWithDistance(placemark.location.coordinate, 10000, 10000);
[_mapview setRegion:viewRegion animated:YES];

MyAnnotation
*annotation=[[MyAnnotation alloc]init];
annotation.state
=allname;
annotation.coordinate
=placemark.location.coordinate;
[_mapview addAnnotation:annotation];


}];
}

第3个buttom(路线(导航))的功能

- (IBAction)geocdeQueryTwo:(id)sender {
if (_txtKey.text==nil|| _txtKey.text.length==0) { //判断输入的地址是否符合规定
return;
}
//CLGeocoder类中有几个方法,一个是把经纬度转化成大家能看懂的信息,比如:city,county,街道等等(反编码),CLGeocoder类中的其他几个方法也可以把city,county等信息直接转化为坐标(编码)
CLGeocoder*geocoder=[[CLGeocoder alloc]init];// 声明GLGeocoder对象并初始化
//开始编码
[geocoder geocodeAddressString:_txtKey.text completionHandler:^(NSArray * _Nullable placemarks, NSError * _Nullable error) {
NSLog(
@"------->%lu",[placemarks count]);

if ([placemarks count]>0) {
CLPlacemark
*placemark=placemarks[0];
//获得该地点的坐标
CLLocationCoordinate2D coordinate=placemark.location.coordinate;
//addressDictionary是该地点的信息通过placemark.addressDictionary获得
NSDictionary *adress=placemark.addressDictionary;
//实例化MKPlacemark对象initWithCoordinate的参数是坐标
MKPlacemark *place=[[MKPlacemark alloc]initWithCoordinate:coordinate addressDictionary:adress];

//设置路线
NSDictionary *optiOns=[[NSDictionary alloc]initWithObjectsAndKeys:MKLaunchOptionsDirectionsModeDriving,MKLaunchOptionsDirectionsModeKey, nil];
MKMapItem
*mapItme2=[[MKMapItem alloc]initWithPlacemark:place];
[mapItme2 openInMapsWithLaunchOptions:options];


}
}];
}

 MKMapItem *mapItme2=[[MKMapItem alloc]initWithPlacemark:place]

实例化MkMapItme MkMapItme类封装了地图上一个点的信息类。我们需要在地图上显示的点封装到MKMApItme对象中,构造器initWithPlacemark:的参数是MKPlacemark类型
[mapItme2 openInMapsWithLaunchOptions:options]
开启iOS系统自带的地图,并用openInMapsWithLaunchOptions方法实例化mapItme2,它的参数是NSDictionary,它可以告诉地图显示哪些信息。

MKLaunchOptionsDirectionsModeKey(路线模式)它有2个值【MKLaunchOptionsDirectionsModeDriving】开车路线【MKLaunchOptionsDirectionsModeWalking】步行路线

MKLaunchOptionsMapTypeKey(地图类型)

MKLaunchOptionsMapCenterKey(地图中心点)

MKLaunchOptionsMapSpanKey(地图跨度)

MKLaunchOptionsShowsTrafficKey(交通状况)

第四个button(我的位置)功能

 

- (IBAction)reverseGeoccode:(id)sender {
[self.locationmanger startUpdatingLocation];

}

 

好了到了目前为止一个小的定位程序做好了运行一下程序吧:测试一下吧

目前定位到重庆市,在text中输入beijing点击一下路线(导航)按钮看看什么效果吧

  点击后

 

程序可以正确运。

这4个按钮的功能都是独立的,他们之间没有联系。其中的代码几乎一样,所以我也就没有过多的解释(其实是我比较懒


推荐阅读
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • IOS开发之短信发送与拨打电话的方法详解
    本文详细介绍了在IOS开发中实现短信发送和拨打电话的两种方式,一种是使用系统底层发送,虽然无法自定义短信内容和返回原应用,但是简单方便;另一种是使用第三方框架发送,需要导入MessageUI头文件,并遵守MFMessageComposeViewControllerDelegate协议,可以实现自定义短信内容和返回原应用的功能。 ... [详细]
  • 使用nodejs爬取b站番剧数据,计算最佳追番推荐
    本文介绍了如何使用nodejs爬取b站番剧数据,并通过计算得出最佳追番推荐。通过调用相关接口获取番剧数据和评分数据,以及使用相应的算法进行计算。该方法可以帮助用户找到适合自己的番剧进行观看。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • 展开全部下面的代码是创建一个立方体Thisexamplescreatesanddisplaysasimplebox.#Thefirstlineloadstheinit_disp ... [详细]
  • 不同优化算法的比较分析及实验验证
    本文介绍了神经网络优化中常用的优化方法,包括学习率调整和梯度估计修正,并通过实验验证了不同优化算法的效果。实验结果表明,Adam算法在综合考虑学习率调整和梯度估计修正方面表现较好。该研究对于优化神经网络的训练过程具有指导意义。 ... [详细]
  • 有没有一种方法可以在不继承UIAlertController的子类或不涉及UIAlertActions的情况下 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • Day2列表、字典、集合操作详解
    本文详细介绍了列表、字典、集合的操作方法,包括定义列表、访问列表元素、字符串操作、字典操作、集合操作、文件操作、字符编码与转码等内容。内容详实,适合初学者参考。 ... [详细]
  • iOS Swift中如何实现自动登录?
    本文介绍了在iOS Swift中如何实现自动登录的方法,包括使用故事板、SWRevealViewController等技术,以及解决用户注销后重新登录自动跳转到主页的问题。 ... [详细]
author-avatar
埃博拉网络科技
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有