展示MKMapView唤起内置导航功能

2018-09-06  本文已影响42人  羊妞麻麻

需求如下:

点击该页面地址或者点击定位地点唤醒地图类APP

屏幕快照 2018-09-05 下午6.10.14.png

地图上面显示的定位地点是从服务端获取的经纬度 比如CLLocationCoordinate2D location1 = CLLocationCoordinate2DMake(39.92, 116.3);

思路:
定义一个view,里面含有mapView相关功能,传入当前需要展示在地图上面的经纬度位置信息。

代码块
需要的框架
CoreLocation.framework
MapKit.framework

.h

#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>

@interface ZHMapManagerView : UIView

@property(nonatomic,strong)NSArray *annotationPins;

//设置目的地的经纬度 展示在地图上面
- (void)setLatitudeAndLongitude:(CLLocationDegrees)latitude
                      longitude:(CLLocationDegrees)longitude;
@end

.m 首先需要导入#import <MapKit/MapKit.h>

@interface ZHMapManagerView ()<MKMapViewDelegate,CLLocationManagerDelegate>
//创建一个位置管理器
@property (nonatomic, strong) CLLocationManager *locationManager;
@property (nonatomic, strong) MKMapView *mapView;

创建mapView

@implementation ZHMapManagerView

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self createMapView];
    }
    return self;
}

- (void)createMapView
{
    self.mapView = [[MKMapView alloc] initWithFrame:self.bounds];
    _mapView.delegate = self;
   //跟踪位置 设置map的跟踪模式
    _mapView.userTrackingMode = MKUserTrackingModeFollow;
   //不显示用户的当前位置
    _mapView.showsUserLocation = NO;
  // 地图类型效果
    _mapView.mapType = MKMapTypeStandard;
    [self addSubview:_mapView];
    
    self.locationManager = [[CLLocationManager alloc] init];
    WS(weakSelf)
 //请求用户授权
    [self openLocationServiceWithBlock:^(BOOL locationIsOpen) {
        if (!locationIsOpen) {
            [weakSelf.locationManager requestWhenInUseAuthorization];
        }
    }];
    
}
- (void)openLocationServiceWithBlock:(void(^)(BOOL locationIsOpen))returnBlock
{
    if ([CLLocationManager locationServicesEnabled])
    {
        CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
        switch (status) {
            case kCLAuthorizationStatusNotDetermined:
                NSLog(@"定位服务授权状态是:用户没有决定是否使用定位服务");
                returnBlock(NO);
                break;
            case kCLAuthorizationStatusRestricted:
                returnBlock(NO);
                NSLog(@"定位服务授权状态是受限制的");
                break;
            case kCLAuthorizationStatusDenied:
                
                NSLog(@"定位服务授权状态已经被用户明确禁止,或者在设置里的定位服务中关闭");
                break;
            case kCLAuthorizationStatusAuthorizedAlways:
                returnBlock(YES);
                NSLog(@"定位服务授权状态已经被用户允许在任何状态下获取位置信息");
                break;
            case kCLAuthorizationStatusAuthorizedWhenInUse:
                NSLog(@"定位服务授权状态仅被允许在使用应用程序的时候");
                returnBlock(YES);
                break;
                
            default:
                break;
        }
    }else
    {
        NSLog(@"定位服务不可用");
    }
    
}

注意事项

需要在info.plist文件中增加这个 请求用户授权


屏幕快照 2018-09-05 下午6.52.21.png

iOS10 对隐私权限的管理
比如访问的摄像头、麦克风等硬件,都需要提前请求应用权限、允许后才可以使用,或者现在要提前声明,虽然以往要求不严格。比如在iOS10中访问通讯录时,强制必须在Info.plist中加入NSContactsUsageDescription等描述,否则应用会崩溃。

定位权限:Privacy - Location When In Use Usage Description 我们需要通过您的地理位置信息获取您周边的相关数据

定位权限: Privacy - Location Always Usage Description 我们需要通过您的地理位置信息获取您周边的相关数据

pragma mark - MKMapViewDelegate

//自定义显示在地图上面大头针的图片样式 我只是改了图片
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
    if ([annotation isKindOfClass:[ZHMyAnnotation class]]) {
        
        static NSString *identifier = @"myAnnotation";
        MKAnnotationView *annotationView =[_mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
        
        if (!annotationView) {
            annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
            annotationView.canShowCallout = NO;//能否显示大头针详情
            
        }
        annotationView.annotation = annotation;
        annotationView.image = ((ZHMyAnnotation *)annotation).image;
        return annotationView;
        
    } else {
        return nil;
    }
}

//点击大头针
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view{
    [self navigateTolatitude:30 longitude:116];
}

pragma mark - CLLocationManagerDelegate

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
    
    if (error) {
        NSLog(@"获取用户当前位置失败");
    }
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
    CLLocation *newLocation = locations[0];
    CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    [geocoder reverseGeocodeLocation:newLocation completionHandler:^(NSArray *array, NSError *error){
        if (array.count > 0){
            CLPlacemark *placemark = [array objectAtIndex:0];
            
            CLLocationDegrees latitude=placemark.location.coordinate.latitude;
            CLLocationDegrees longitude=placemark.location.coordinate.longitude;
            
            NSString *city = [NSString stringWithFormat:@"%@%@",placemark.administrativeArea ? placemark.administrativeArea : @"",placemark.locality ? placemark.locality : @""];
            
            NSLog(@"adress---%@",[NSString stringWithFormat:@"%@ %@ %@ %@",placemark.country,city,placemark.name,placemark.thoroughfare]);
            
            NSLog(@"%@",[NSString stringWithFormat:@"经度:%.3f,纬度:%.3f",longitude,latitude]);
            
        }
        else if (error == nil && [array count] == 0)
        {
            NSLog(@"地图加载失败");
        }
        else if (error != nil)
        {
           NSLog(@"地图加载失败");
        }
    }];
    
    [manager stopUpdatingLocation];
    
}

地理编码和反地理编码都使用CLGeocoder类来实现.

反地理编码

使用reverseGeocodeLocation: completionHandler: 方法.将一个包含经纬度的CLLocation传进去,得到位置信息,就是反地理编码。

在得到的CLPlacemark中取出name信息即可。如上代码⬆️

地理编码

使用 geocodeAddressString: completionHandler: 方法.将一个地名字符串转换为经纬度。

在此方法中得到一个装着CLPlacemark的数组。一个CLPlacemark表示一个地理坐标,有位置信息(经纬度),以及地理位置的详情。将CLPlacemark中的经纬度取出,就完成了地理编码

实现导航功能

本次需求是唤起苹果内置的导航即可。地图导航所需的数据拿不到,交由苹果处理,在中国苹果交友高德地图处理。由于封装的比较好,我们本质上只需要一行代码:
MKMapItem openMapsWithItems: launchOptions:

代码块:

- (void)navigateTolatitude:(CLLocationDegrees)latitude
                 longitude:(CLLocationDegrees)longitude
{
    MKMapItem *currentLocation =[MKMapItem mapItemForCurrentLocation];
    MKMapItem *toLocation = [[MKMapItem alloc] initWithPlacemark:[[MKPlacemark alloc] initWithCoordinate:CLLocationCoordinate2DMake(latitude, longitude) addressDictionary:nil]];
    
    [MKMapItem openMapsWithItems:@[currentLocation,toLocation] launchOptions:@{MKLaunchOptionsDirectionsModeKey:MKLaunchOptionsDirectionsModeDriving,MKLaunchOptionsShowsTrafficKey:[NSNumber numberWithBool:YES]}];
}

1.首先获取地理编码目的地位置
使用CLGeocoder进行地理编码,得到CLPlacemark, 转换CLPlacemark --> MKPlacemark
MKPlacemark *mkPlacemark = [[MKPlacemark alloc] initWithPlacemark:placemark];

2、获取当前位置和目的位置的mapItem
//当前位置
MKMapItem *currentLocation =[MKMapItem mapItemForCurrentLocation];

//目的地位置
MKMapItem *toLocation = [[MKMapItem alloc] initWithPlacemark:[[MKPlacemark alloc] initWithCoordinate:CLLocationCoordinate2DMake(latitude, longitude) addressDictionary:nil]];

3、开始导航
第一个参数传入目的地和当前位置的数组,第二个是选项的字典。

[MKMapItem openMapsWithItems:@[currentLocation,toLocation] launchOptions:@{MKLaunchOptionsDirectionsModeKey:MKLaunchOptionsDirectionsModeDriving,MKLaunchOptionsShowsTrafficKey:[NSNumber numberWithBool:YES]}];

//keys

MKLaunchOptionsMapCenterKey:地图中心的坐标(NSValue)

MKLaunchOptionsMapSpanKey:地图显示的范围(NSValue)

MKLaunchOptionsShowsTrafficKey:是否显示交通信息(boolean NSNumber)

//MKLaunchOptionsDirectionsModeKey: 导航类型(NSString)

{

MKLaunchOptionsDirectionsModeDriving:驾车

MKLaunchOptionsDirectionsModeWalking:步行

}

//MKLaunchOptionsMapTypeKey:地图类型(NSNumber)

enum {

MKMapTypeStandard = 0,

MKMapTypeSatellite,

MKMapTypeHybrid

};//MKLaunchOptionsCameraKey 3D地图效果

以上是针对app内展示经纬度和导航去这里的基本代码。

上一篇下一篇

猜你喜欢

热点阅读