[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 ...
随机推荐
- 127.0.0.1、0.0.0.0和本机IP地址的区别和使用
一.表面上的区别如下: 首先假设本机有多个网卡:eth0 :192.168.0.1 eth1:192.168.1.1 lo: 127.0.0.1 0.0.0.0 不能ping通,代 ...
- oracle:如何用sql生成日历
BI分析中,经常需要将事实表与时间维度表关联起来,按年/月/日来逐层展示,常用的做法是创建一张日历表,结构类似如下: create table T_BAS_CALENDAR ( d_year ) no ...
- ReactNative真机运行运行
注意在iOS设备上运行React Native应用需要一个Apple Developer account并且把你的设备注册为测试设备.本向导只包含React Native相关的主题. 译注:从XCod ...
- SQL基础之数据库
1.基础概念 首先要强调一点,就是我们的数据库是由数据库系统来管理的,我们登入数据库并在其上进行操作时最终均要通过数据库系统来完成.可以理解成在数据库上进行操作的是客户端,数据库系统是服务端.一个数据 ...
- Vue学习笔记-2
前言 本文非vue教程,仅为学习vue过程中的个人理解与笔记,有说的不正确的地方欢迎指正讨论 1.computed计算属性函数中不能使用vm变量 在计算属性的函数中,不能使用Vue构造函数返回的vm变 ...
- 多线程处理中Future的妙用
java 中Future是一个未来对象,里面保存这线程处理结果,它像一个提货凭证,拿着它你可以随时去提取结果.在两种情况下,离开Future几乎很难办.一种情况是拆分订单,比如你的应用收到一个批量订单 ...
- JavaScript函数劫持
一.为什么我会写这篇文章 这篇文章其实是在一个偶然的机会下发现了居然有JavaScript劫持这种东西,虽然这种东西在平时用的比较少,而且一般实用价值不高,但是在一些特殊的情况下还是要使用到的,所以在 ...
- 【前端积累】createElement createTextNode
<!DOCTYPE html> <html><!--树根--> <head> <meta charset="utf-8"> ...
- golang: 把sql结果集以json格式输出
func getJSON(sqlString string) (string, error) { stmt, err := db.Prepare(sqlString) if err != nil { ...
- Android 轻量级输入校验库:Fire Eye
Fire Eye是一款轻量级简单易用的Android校验库. FireEye 2.0 在 1.0 的基础上,全部重写了代码,并优化了架构,性能上和逻辑上都大大提升.只需要几行代码,即可验证用户输入,并 ...