[iOS 利用MapKit和CoreLocation框架打造精简的定位和导航]
运行效果:
一.利用<CoreLocation/CoreLocation.h>定位
创建变量 CLLocationManager *locationManager ,并加入<CLLocationManagerDelegate>协议
以下是Viewdidload里需要初始化的参数:
self.locationManager = [[CLLocationManager alloc]init];
[self.locationManager setDelegate:self];
[self.locationManager requestAlwaysAuthorization];
[self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
[self.locationManager setDistanceFilter:kCLDistanceFilterNone];
if ([locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
[locationManager requestWhenInUseAuthorization];
}
[self.locationManager startUpdatingLocation];
开始定位后,结果会用过这个函数回调,locations数组含有一切定位信息:时间,经纬度等
// Location Manager Delegate Methods
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
NSLog(@"%@", [locations lastObject]);
}
需要注意的是:在iOS8之后,使用地图需要请求权限,需要在info.plist文件中加入2个字段:
NSLocationWhenInUseDescription
NSLocationAlwaysUsageDescription
并且在使用定位前需要运行函数:
[self.locationManager requestAlwaysAuthorization];
或 [locationManager requestWhenInUseAuthorization];
二、 利用Mapkit使用地图服务
创建变量 MKMapView *regionMapView ,并加入<MKMapViewDelegate>协议
初始化参数:
self.regionMapView.delegate = self;
self.regionMapView.showsUserLocation = YES;
关于地图,有个大坑是目前各大地图的坐标系都不一样。
国际标准是WGS-84,比如谷歌、苹果地图提供的API等都是基于这个坐标的。
天朝为了“照顾大家安全”,立了个新标准GCJ-02,比如高德地图就是基于它的。也就是所谓的火星坐标系。另外百度为了"更好地保护大家隐私",也有自己的二次加密后的标准BD-09.
如果直接使用国外那些不安全的地图提供的经纬度来插到我们天朝地图上,很可能就存在很大偏移。所以作为地图开发者我们首先要熟练运用6种坐标互相转换算法。
国外《-》高德 高德《-》百度 百度《-》国外
所以上面利用CoreLocation定位出的经纬度显示是有偏差的(定位出的是WGC-84,国内目前是高德地图),要想正确显示就要用算法转换(WGC-84转GCJ-02)。
或者有另外一个方法,利用MapKit的回调函数,得到的结果是经过转换的。可见MapKit内部应该是已经调用了定位的。
#pragma mark MKMapViewDelegate -user location定位变化
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{
_userlocation=userLocation;
self.nowCoords = [userLocation coordinate];
NSLog(@"定位到当前位置");
_updateInt++;
//放大地图到自身的经纬度位置。
self.userRegion = MKCoordinateRegionMakeWithDistance(self.nowCoords, , );
if(_updateInt==||_iffollowed==YES){
[self.regionMapView setRegion:self.userRegion animated:NO];
}
//仅在打开地图后,第一次更新地理信息时,确定使用者的大致地理位置
if (_updateInt<=) {
//CLGeocoder 是谷歌接口通过经纬度查询大致地址
NSLog(@"通过经纬度查询地理信息");
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:[userLocation location] completionHandler:^(NSArray *array, NSError *error) {
if (array.count > ) {
CLPlacemark *placemark = [array objectAtIndex:];
_myregion=[placemark region];
NSString *region = [placemark.addressDictionary objectForKey:@"SubLocality"];
NSString *address = [placemark.addressDictionary objectForKey:@"Name"];
self.regionStr = region;
self.addressStr = address;
self.city = placemark.locality;
NSLog(@"当前使用者所在:地点名:%@,地址:%@,城市:%@",self.regionStr,self.addressStr,self.city);
}else{
self.regionStr = @"";
self.addressStr = @"";
self.city = @"";
NSLog(@"未查询到有效地址");
}
}];
}
//判断是否是否要根据运动路线绘图
if (![[NSString stringWithFormat:@"%0.8f",[[userLocation location] coordinate].latitude] isEqualToString:[NSString stringWithFormat:@"%0.8f",self.centerCoordinate.latitude]] ) { //做点什么
return;
}
}
使用地图主要有2个基本:(1)地理编码:地址转经纬度。
(2)地理反编码:经纬度转成地址。
(1)地址转经纬度的方法(具体功能为:输入查找地点,然后显示在地图上)
方法有2个:一个是采用MK框架自带的接口 CLGeocoder,该接口还有其他的用法,按住CMD+点击CLGeocoder就会出现该类的接口。
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:@"屏峰" completionHandler:^(NSArray *placemarks, NSError *error) {
if ([placemarks count] > && error == nil){
NSLog(@"Found %lu placemark(s).", (unsigned long)[placemarks count]);
CLPlacemark *firstPlacemark = [placemarks objectAtIndex:];
NSLog(@"Longitude = %f", firstPlacemark.location.coordinate.longitude);
NSLog(@"Latitude = %f", firstPlacemark.location.coordinate.latitude);
}
else if ([placemarks count] == && error == nil){
NSLog(@"Found no placemarks.");
}
else if (error != nil){
NSLog(@"An error occurred = %@", error);
}
}];
另一种就是使用百度或者其他地图的接口,比如我的Demo中使用的就是百度接口,不方便的是,百度接口获得的经纬度需要转换才能正确的“插”在高德上。
百度接口为:http://api.map.baidu.com/place/search?&query=西湖®ion=杭州&output=json&key=bqApldE1oh6oBb98VYyIfy9S
主要是4个参数。效果如下:
(2)地理反编码:经纬度转成地址。
方法同上,反过来也有接口。
第一种是Mapkit接口:
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:[userLocation location] completionHandler:^(NSArray *array, NSError *error) {
if (array.count > ) {
CLPlacemark *placemark = [array objectAtIndex:];
_myregion=[placemark region];
NSString *region = [placemark.addressDictionary objectForKey:@"SubLocality"];
NSString *address = [placemark.addressDictionary objectForKey:@"Name"];
self.regionStr = region;
self.addressStr = address;
self.city = placemark.locality;
NSLog(@"当前使用者所在:地点名:%@,地址:%@,城市:%@",self.regionStr,self.addressStr,self.city);
}else{
self.regionStr = @"";
self.addressStr = @"";
self.city = @"";
NSLog(@"未查询到有效地址");
}
}];
第二种是其他接口,同样传入参数是经纬度,返回地理信息。
效果:
三、地图操作:
1.地图依据经纬度插点:
主要利用Mapkit接口:(如果要发现某个类有哪些好玩的接口可以按住CMD+该类名进去看看有哪些函数,然后去搜搜这些函数的用法或看看官方文档)
[map addAnnotation:annotation];
后者,也就是那个棒棒糖属于MKAnnotation类,这个类有很多自定义UI的例子,通过在上面加label,加button,可以扩展获得很多功能。(比如显示该地点的具体图片文字信息等)
2.地图画线进行导航:
这些奇葩的功能都是由你所使用的地图API提供的,我这里使用的Mapkit,所以我使用的就是Mapkit的画线接口。
另外神奇的是,你可以通过[UIApplication sharedApplication]使用其他地图来构造导航路线。
(1)把导航的繁重任务交给其他专业的地图吧,这里只是大概代码(具体参见我的DEMO):
-(void)doAcSheet{
NSArray *appListArr = [CheckInstalledMapAPP checkHasOwnApp];
NSString *sheetTitle = [NSString stringWithFormat:@"导航到 %@",[self.navDic objectForKey:@"address"]];
UIActionSheet *sheet;
if ([appListArr count] == ) {
sheet = [[UIActionSheet alloc] initWithTitle:sheetTitle delegate:self cancelButtonTitle:@"取消" destructiveButtonTitle:nil otherButtonTitles:appListArr[],appListArr[], nil];
}else if ([appListArr count] == ){
sheet = [[UIActionSheet alloc] initWithTitle:sheetTitle delegate:self cancelButtonTitle:@"取消" destructiveButtonTitle:nil otherButtonTitles:appListArr[],appListArr[],appListArr[], nil];
}else if ([appListArr count] == ){
sheet = [[UIActionSheet alloc] initWithTitle:sheetTitle delegate:self cancelButtonTitle:@"取消" destructiveButtonTitle:nil otherButtonTitles:appListArr[],appListArr[],appListArr[],appListArr[], nil];
}else if ([appListArr count] == ){
sheet = [[UIActionSheet alloc] initWithTitle:sheetTitle delegate:self cancelButtonTitle:@"取消" destructiveButtonTitle:nil otherButtonTitles:appListArr[],appListArr[],appListArr[],appListArr[],appListArr[], nil];
}
sheet.actionSheetStyle = UIActionSheetStyleBlackOpaque;
[sheet showInView:self.view];
} -(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{
NSString *btnTitle = [actionSheet buttonTitleAtIndex:buttonIndex];
if (buttonIndex == ) {
CLLocationCoordinate2D to;
to.latitude = _naviCoordsGd.latitude;
to.longitude = _naviCoordsGd.longitude;
MKMapItem *currentLocation = [MKMapItem mapItemForCurrentLocation];
MKMapItem *toLocation = [[MKMapItem alloc] initWithPlacemark:[[MKPlacemark alloc] initWithCoordinate:to addressDictionary:nil]]; toLocation.name = _addressStr;
[MKMapItem openMapsWithItems:[NSArray arrayWithObjects:currentLocation, toLocation, nil] launchOptions:[NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:MKLaunchOptionsDirectionsModeDriving, [NSNumber numberWithBool:YES], nil] forKeys:[NSArray arrayWithObjects:MKLaunchOptionsDirectionsModeKey, MKLaunchOptionsShowsTrafficKey, nil]]];
}
if ([btnTitle isEqualToString:@"google地图"]) {
NSString *urlStr = [NSString stringWithFormat:@"comgooglemaps://?saddr=%.8f,%.8f&daddr=%.8f,%.8f&directionsmode=transit",self.nowCoords.latitude,self.nowCoords.longitude,self.naviCoordsGd.latitude,self.naviCoordsGd.longitude];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlStr]];
}else if ([btnTitle isEqualToString:@"高德地图"]){
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"iosamap://navi?sourceApplication=broker&backScheme=openbroker2&poiname=%@&poiid=BGVIS&lat=%.8f&lon=%.8f&dev=1&style=2",self.addressStr,self.naviCoordsGd.latitude,self.naviCoordsGd.longitude]];
[[UIApplication sharedApplication] openURL:url]; }else if ([btnTitle isEqualToString:@"百度地图"]){
double bdNowLat,bdNowLon;
bd_encrypt(self.nowCoords.latitude, self.nowCoords.longitude, &bdNowLat, &bdNowLon); NSString *stringURL = [NSString stringWithFormat:@"baidumap://map/direction?origin=%.8f,%.8f&destination=%.8f,%.8f&&mode=driving",bdNowLat,bdNowLon,self.naviCoordsBd.latitude,self.naviCoordsBd.longitude];
NSURL *url = [NSURL URLWithString:stringURL];
[[UIApplication sharedApplication] openURL:url];
}else if ([btnTitle isEqualToString:@"显示路线"]){
[self drawRout];
}
}
(2)还是试试自己画线好了O(∩_∩)O:(主要是提供两个点的参数)
-(void)drawRout{
MKPlacemark *fromPlacemark = [[MKPlacemark alloc] initWithCoordinate:_nowCoords addressDictionary:nil];
MKPlacemark *toPlacemark = [[MKPlacemark alloc] initWithCoordinate:_naviCoordsGd addressDictionary:nil];
MKMapItem *fromItem = [[MKMapItem alloc] initWithPlacemark:fromPlacemark];
MKMapItem *toItem = [[MKMapItem alloc] initWithPlacemark:toPlacemark]; [self.regionMapView removeOverlays:self.regionMapView.overlays];
[self findDirectionsFrom:fromItem to:toItem]; }
#pragma mark - ios7路线绘制方法
-(void)findDirectionsFrom:(MKMapItem *)from to:(MKMapItem *)to{
MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init];
request.source = from;
request.destination = to;
request.transportType = MKDirectionsTransportTypeWalking;
if (ISIOS7) {
request.requestsAlternateRoutes = YES;
} MKDirections *directions = [[MKDirections alloc] initWithRequest:request];
//ios7获取绘制路线的路径方法
[directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) {
if (error) {
NSLog(@"error:%@", error);
}
else {
MKRoute *route = response.routes[];
[self.regionMapView addOverlay:route.polyline];
}
}];
}
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView
rendererForOverlay:(id<MKOverlay>)overlay{
MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithOverlay:overlay];
renderer.lineWidth = 5.0;
renderer.strokeColor = [UIColor redColor];
return renderer;
}
GithubDemo:https://github.com/rayshen/ShenMapViewDemo
[iOS 利用MapKit和CoreLocation框架打造精简的定位和导航]的更多相关文章
- ios开发-MapKit(地图框架)使用简介
我们使用app的时候,很多软件都自带了地图功能.我们可以看到自己的位置,看到周围商场等信息.我们也可以导航,划线等. 其实苹果的MapKit使用起来还是很简单的.这里简单的介绍一下. 0.使用前准备 ...
- iOS:地图:MapKit和CoreLocation
地图:MapKit和CoreLocation 简介: 现在很多的社交软件都引入了地图和定位功能,要想实现这2大功能,那就不得不学习其中的2个框架:MaKit和CoreLocation CoreLoca ...
- 【高德API】如何利用MapKit开发全英文检索的iOS地图
原文:[高德API]如何利用MapKit开发全英文检索的iOS地图 制作全英文地图的展示并不困难,但是要制作全英文的数据检索列表,全英文的信息窗口,你就没办法了吧.告诉你,我有妙招!使用iOS自带的M ...
- MapKit/CoreLocation框架 总结
MapKit/CoreLocation框架 /*英译 core:核心 track:踪迹 current:当前 statellite:卫星 hybird:混合 region:范围 annotation ...
- 利用 Dijit 组件框架打造丰富的用户界面
原文出处:Joe Lennon 从头开始学习 Dojo,第 3 部分 利用 Dijit 组件框架打造丰富的用户界面 Dijit 是什么? Dijit 是 Dojo 工具包的富组件用户界面库.这些组件完 ...
- IOS CoreLocation框架的使用(用于地理定位)
● 在移动互联网时代,移动app能解决用户的很多生活琐事,比如 ● 导航:去任意陌生的地方 ● 周边:找餐馆.找酒店.找银行.找电影院 ● 在上述应用中,都用到了地图和定位功能,在iOS开发中 ...
- iOS地图----MapKit框架
1.MapKit框架使用前提 ①导入框架 ②导入主头文件 #import <MapKit/MapKit.h> ③MapKit框架使用须知 MapKit框架中所有数据类型的前缀都是MK Ma ...
- iOS定位--CoreLocation框架
CoreLocation框架的使用 // 首先导入头文件 #import <CoreLocation/CoreLocation.h> CoreLocation框架中所有数据类型的前缀都是C ...
- CoreLocation框架的使用
CoreLocation框架使用 一.地图和定位的简介 1.应用场景 周边:找餐馆/找KTV/找电影院(团购APP) 导航:根据用户设定的起点和终点,进行路线规划,并指引用户如何到达(地图APP) 2 ...
随机推荐
- script实现的日期表示
function clockon(bgclock){ var now=new Date(); var year=now.getYear(); var month=now.getMonth(); var ...
- Java并发编程实战(使用synchronized实现同步方法)
本文介绍java最基本的同步方式,即使用synchronized关键字来控制一个方法的并发访问,如果一个对象已用synchronized关键字声明,那么只有一个执行线程允许去访问它,其它试图访问这个对 ...
- [转]关于Python中的yield
在介绍yield前有必要先说明下Python中的迭代器(iterator)和生成器(constructor). 一.迭代器(iterator) 在Python中,for循环可以用于Python中的任何 ...
- DOM Document节点类型详解
在前面 DOM 概况 中,我们知道了 DOM 总共有 12 个节点类型,今天我们就来讲下 DOM 中最重要的节点类型之一的 document 节点类型. 1.概况 Javascript 通过 Docu ...
- Github优秀java项目集合(中文版) - 涉及java所有的知识体系
Java资源大全中文版 我想很多程序员应该记得 GitHub 上有一个 Awesome - XXX 系列的资源整理.awesome-java 就是 akullpp 发起维护的 Java 资源列表,内容 ...
- 是什么时候开始学习gulp了
转自:http://www.ydcss.com/archives/18 简介: gulp是前端开发过程中对代码进行构建的工具,是自动化项目的构建利器:她不仅能对网站资源进行优化,而且在开发过程中很多重 ...
- [MCSM] Slice Sampler
1. 引言 之前介绍的MCMC算法都具有一般性和通用性(这里指Metropolis-Hasting 算法),但也存在一些特殊的依赖于仿真分布特征的MCMC方法.在介绍这一类算法(指Gibbs samp ...
- Putty SSH简单使用
本地的puttygen生出的秘钥,公钥传到服务器上连接会报错 Server refused our key. 一般我们建议都在服务器上生成秘钥,把私钥下载下来.加载到putty认证中 01.在服务器上 ...
- directly receive json data from javascript in mvc
if you send json data to mvc,how can you receive them and parse them more simply? you can do it like ...
- 0929mysql前缀索引如何找到合适的位数
前缀索引,是指对于VARCHAR/TEXT/BLOB类型的字段建立索引时一般都会选择前N个字符作为索引.索引很长的字符列,会让索引变得大且慢.索引开始的部分字符,这样可以大大节约索引空间,从而提高索引 ...