[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, 200, 200);
    if(_updateInt==1||_iffollowed==YES){
        [self.regionMapView setRegion:self.userRegion animated:NO];
    }
    //仅在打开地图后,第一次更新地理信息时,确定使用者的大致地理位置
    if (_updateInt<=1) {
        //CLGeocoder 是谷歌接口通过经纬度查询大致地址
        NSLog(@"通过经纬度查询地理信息");
        CLGeocoder *geocoder = [[CLGeocoder alloc] init];
        [geocoder reverseGeocodeLocation:[userLocation location] completionHandler:^(NSArray *array, NSError *error) {
            if (array.count > 0) {
                CLPlacemark *placemark = [array objectAtIndex:0];
                _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] > 0 && error == nil){
            NSLog(@"Found %lu placemark(s).", (unsigned long)[placemarks count]);
            CLPlacemark *firstPlacemark = [placemarks objectAtIndex:0];
            NSLog(@"Longitude = %f", firstPlacemark.location.coordinate.longitude);
            NSLog(@"Latitude = %f", firstPlacemark.location.coordinate.latitude);
        }
        else if ([placemarks count] == 0 && error == nil){
            NSLog(@"Found no placemarks.");
        }
        else if (error != nil){
            NSLog(@"An error occurred = %@", error);
        }
    }];

  另一种就是使用百度或者其他地图的接口,比如我的Demo中使用的就是百度接口,不方便的是,百度接口获得的经纬度需要转换才能正确的“插”在高德上。

百度接口为:http://api.map.baidu.com/place/search?&query=西湖&region=杭州&output=json&key=bqApldE1oh6oBb98VYyIfy9S

主要是4个参数。效果如下:

 (2)地理反编码:经纬度转成地址。

方法同上,反过来也有接口。

    第一种是Mapkit接口:

CLGeocoder *geocoder = [[CLGeocoder alloc] init];
        [geocoder reverseGeocodeLocation:[userLocation location] completionHandler:^(NSArray *array, NSError *error) {
            if (array.count > 0) {
                CLPlacemark *placemark = [array objectAtIndex:0];
                _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(@"未查询到有效地址");
            }
        }];

第二种是其他接口,同样传入参数是经纬度,返回地理信息。

比如百度:http://api.map.baidu.com/geocoder/v2/?ak=E4805d16520de693a3fe707cdc962045&callback=renderReverse&location=39.983424,116.322987&output=json&pois=1

效果:

三、地图操作:

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] == 2) {
        sheet = [[UIActionSheet alloc] initWithTitle:sheetTitle delegate:self cancelButtonTitle:@"取消" destructiveButtonTitle:nil otherButtonTitles:appListArr[0],appListArr[1], nil];
    }else if ([appListArr count] == 3){
        sheet = [[UIActionSheet alloc] initWithTitle:sheetTitle delegate:self cancelButtonTitle:@"取消" destructiveButtonTitle:nil otherButtonTitles:appListArr[0],appListArr[1],appListArr[2], nil];
    }else if ([appListArr count] == 4){
        sheet = [[UIActionSheet alloc] initWithTitle:sheetTitle delegate:self cancelButtonTitle:@"取消" destructiveButtonTitle:nil otherButtonTitles:appListArr[0],appListArr[1],appListArr[2],appListArr[3], nil];
    }else if ([appListArr count] == 5){
        sheet = [[UIActionSheet alloc] initWithTitle:sheetTitle delegate:self cancelButtonTitle:@"取消" destructiveButtonTitle:nil otherButtonTitles:appListArr[0],appListArr[1],appListArr[2],appListArr[3],appListArr[4], nil];
    }
    sheet.actionSheetStyle = UIActionSheetStyleBlackOpaque;
    [sheet showInView:self.view];
}

-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{
    NSString *btnTitle = [actionSheet buttonTitleAtIndex:buttonIndex];
    if (buttonIndex == 0) {
            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[0];
            [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

时间: 2024-08-04 10:18:26

[iOS 利用MapKit和CoreLocation框架打造精简的定位和导航]的相关文章

【iOS开发-109】CoreLocation框架的两个主要类CLLocationManager和CLGeoCoder介绍

CoreLocation框架主要由两个常用的类,一个是CLLocationManager,一个是CLGeoCoder. (1)CoreLocation的使用,先导入CoreLocation框架. (2)一般是利用位置管理器来操作,即CLLocationManager --开启,就是startUpdatingLocation:关闭,就是stopUpdatingLocation --可以先判断位置服务是否开启locationServicesEnabled,如果没开启,直接返回空,不操作. --iOS

iOS核心笔记—CoreLocation框架-基础

1.CoreLocation框架简介: ?了解:在iOS开发中,要想使用地图和定位功能,必须基于2个框架进行开发.CoreLocation框架:主要用于地理定位:MapKit框架:主要用于地图展示. 1-1.CoreLocation框架功能: 功能 作用 地理定位 定位用户所在位置,获取对应的经纬度.海拔等位置信息 区域监听 事先在APP内部通过代码指定一个区域,当用户进入.或离开该区域的时候,可以通过对应的代理方法监听到用户的位置 地理编码 将详细的位置信息转换为对应的经纬度,即:位置信息 -

iOS:地图:MapKit和CoreLocation

地图:MapKit和CoreLocation 简介: 现在很多的社交软件都引入了地图和定位功能,要想实现这2大功能,那就不得不学习其中的2个框架:MaKit和CoreLocation CoreLocation框架可以使用硬件设备来进行定位服务 MapKit框架能够使应用程序做一些地图展示与交互的相关功能 几乎所有的iOS设备都支持位置服务,不过在使用位置服务之前,最好检查一下可用性 手机定位的三种方式:手机基站.WIFI.GPS 添加框架: #import <MapKit/MapKit.h>

【高德API】如何利用MapKit开发全英文检索的iOS地图

原文:[高德API]如何利用MapKit开发全英文检索的iOS地图 制作全英文地图的展示并不困难,但是要制作全英文的数据检索列表,全英文的信息窗口,你就没办法了吧.告诉你,我有妙招!使用iOS自带的MapKit来展示全球英文底图,结合上高德API的中英文检索功能,就能打造POI数据最丰富,英文展示全方位的纯英文地图啦!看看截图,是不是浑然天成? ----------------------------------------------------------------------------

iOS地图----MapKit框架

1.MapKit框架使用前提 ①导入框架 ②导入主头文件 #import <MapKit/MapKit.h> ③MapKit框架使用须知 MapKit框架中所有数据类型的前缀都是MK MapKit有一个比较重要的UI控件,专门用于地图显示 ④MapKit框架包含CLLocation 2.设置地图的类型 可以通过设置MKMapView的mapType设置地图类型 typedef enum : NSUInteger { MKMapTypeStandard , 标准(默认) MKMapTypeSat

iOS定位--CoreLocation框架

CoreLocation框架的使用 // 首先导入头文件 #import <CoreLocation/CoreLocation.h> CoreLocation框架中所有数据类型的前缀都是CL CoreLocation中使用CLLocationManager对象来做用户定位 1.CLLocationManager的使用 CLLocationManager的常用操作 /** * 定位管理者,全局变量强引用,防止销毁 */ @property (nonatomic ,strong) CLLocati

IOS中CoreLocation框架地理定位

1.CoreLocation框架使用前提: #import <CoreLocation/CoreLocation.h> CoreLocation框架中所有数据类型的前缀都是CL ,CoreLocation中使用CLLocationManager对象来做用户定位 2.CLLocationManager的常用操作: 开始用户定位 - (void)startUpdatingLocation; 停止用户定位 - (void) stopUpdatingLocation; 当调用了startUpdatin

iOS CoreLocation框架

官方参考文档:https://developer.apple.com/documentation/corelocation/cllocationmanager 导入CoreLocation框架和对应的主头文件 #import <CoreLocation/CoreLocation.h> 创建CLLcationManager对象,并设置代理 _locationM = [[CLLocationManager alloc] init]; _locationM.delegate = self; if (

iOS开发-常用第三方开源框架介绍(你了解的ios只是冰山一角)

iOS开发-常用第三方开源框架介绍(你了解的ios只是冰山一角) 2015-04-05 15:25 2482人阅读 评论(1) 收藏 举报开源框架 图像: 1.图片浏览控件MWPhotoBrowser       实现了一个照片浏览器类似 iOS 自带的相册应用,可显示来自手机的图片或者是网络图片,可自动从网络下载图片并进行缓存.可对图片进行缩放等操作.      下载:https://github.com/mwaterfall/MWPhotoBrowser目前比较活跃的社区仍旧是Github,