地图相关 MapKit框架

本文介绍iOS中MapKit框架的高级应用,包括如何实现线路导航和兴趣点搜索功能。详细介绍了各相关类的使用方法,并提供了具体的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

介绍

1.概念

  • 导入头文件 #import <MapKit/MapKit.h>
  • MapKit框架中所有数据类型的前缀都是MK
  • MapKit有一个比较重要的UI控件 :MKMapView,专门用于地图显示

mapView


2.逻辑结构:


逻辑结构

MKMapView控件对象的属性和方法

属性:

1.设置用户定位模式

@property (nonatomic) MKUserTrackingMode userTrackingMode;

MKUserTrackingMode 枚举:
MKUserTrackingModeNone 不定位
MKUserTrackingModeFollow 定位
MKUserTrackingModeFollowWithHeading 定位并且显示方向

2.设置地图类型

@property (nonatomic) MKMapType mapType;

MKMapType 枚举:
MKMapTypeStandard :普通地图(左图)
MKMapTypeSatellite :卫星云图 (中图)
MKMapTypeHybrid :普通地图覆盖于卫星云图之上(右图)


MKMapType


剩下两种MKMapTypeSatelliteFlyover和MKMapTypeHybridFlyover在中国区无法使用


剩下两种

3.定位的用户坐标

@property (nonatomic, readonly) MKUserLocation *userLocation;

4.当前界面地图的中心坐标

@property (nonatomic) CLLocationCoordinate2D centerCoordinate;

例子:使用当前地图界面的中心点回归到用户的坐标(只能中心点回归,范围回归需要设置region属性)

self.mapView.centerCoordinate = self.mapView.userLocation.location.coordinate;

5.设置代理

@property (nonatomic, weak, nullable) id <MKMapViewDelegate> delegate;

6.设置范围

@property (nonatomic) MKCoordinateRegion region;

MKCoordinateRegion 区域结构体包含 CLLocationCoordinate2D 经纬度( latitude 纬度, longitude 经度) MKCoordinateSpan 范围跨度 ,1度= 111千米( latitudeDelta 纬度跨度 , longitudeDelta 经度跨度) 两个结构体,每个结构体都是一个double值,所以region需要四个double
Span系统默认值为 MKCoordinateSpanMake(0.021256, 0.016093)

iOS 9.0新增属性(注意添加版本判断~!)

7.显示交通情况

@property (nonatomic) BOOL showsTraffic

显示交通状况


8.显示比例尺

@property (nonatomic) BOOL showsScale;



比例尺随缩放变化

9.显示指南针(iOS9 默认YES,屏幕旋转手势之后出现,如果点击会校正方向)

@property (nonatomic) BOOL showsCompass;

指南针

方法:

1.以动画的方式设置区域,用于地图中心定位到用户所在位置

- (void)setRegion:(MKCoordinateRegion)region animated:(BOOL)animated;

2.在地图上添加一个大头针

- (void)addAnnotation:(id <MKAnnotation>)annotation;

3.将指定view上的point点转换成地图上的经纬度坐标,一般在touchesBegan中调用

- (CLLocationCoordinate2D)convertPoint:(CGPoint)point toCoordinateFromView:(nullable UIView *)view;

4.从缓存池中查找指定ID的自定义大头针模型

- (nullable MKAnnotationView *)dequeueReusableAnnotationViewWithIdentifier:(NSString *)identifier;

代理方法:MKMapViewDelegate

1.完成用户位置更新的时候会调用此方法,参数 MKUserLocation:用户定位位置的大头针模型

- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation;

2.当地图的显示区域发生改变的时候调用

- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated;

3.当添加大头针模型的时候调用此方法, 在大头针视图添加到地图之前调用,可用于自定义大头针(类似于cell创建方式),参数 annotation 为插到地图上的大头针模型,也包括系统的
如果返回nil,代表用户没有自定义需求,样式由系统处理。

- (nullable MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation;

注意:也包括系统定位用的大头针模型MKUserLocation !如果不想将其自定义要进行类型筛选判断

if ([annotation isKindOfClass:[MKUserLocation class]]) {
        return nil;
    }

4.在添加大头针图像出现之前调用,可以设置大头针的掉落效果
参数 views 大头针掉落后的图像,将大头针的y值设置为0(顶部),再动画回到原来的位置可实现
注意:不要将系统定位的大头针设置了动画效果

- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray<MKAnnotationView *> *)views;
MKUserLocation 也是一种大头针,用于显示用户位置的大头针模型,(就是默认周围放光的定位大头针),专门控制定位大头针显示的,可获取大头针的位置信息(用户定位信息)

重要属性,可以获取地图上的经纬度

@property (readonly, nonatomic, nullable) CLLocation *location;
@property (readonly, nonatomic, getter=isUpdating) BOOL updating;
@property (readonly, nonatomic, nullable) CLHeading *heading;
@property (nonatomic, copy, nullable) NSString *title;
@property (nonatomic, copy, nullable) NSString *subtitle;

例子:显示用户位置

例子
//拖一个mapView控件,一定要导入框架
@property (weak, nonatomic) IBOutlet MKMapView *mapView;

//1. 显示用户位置,创建位置管理器请求授权
self.locationManager = [CLLocationManager new];
if ([self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
    [self.locationManager requestWhenInUseAuthorization];
}
//2. 设置显示用户位置 用户跟踪模式
self.mapView.userTrackingMode = MKUserTrackingModeFollow;
//3. 设置代理 获取数据
self.mapView.delegate = self;

//代理方法,完成用户位置更新的时候会调用
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{
    //1. 创建地理编码对象
    CLGeocoder *geocoder = [CLGeocoder new];
    //2. 调用方法,反地理编码
    [geocoder reverseGeocodeLocation:userLocation.location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
        //3. 防错输出
        if (placemarks.count == 0 || error) {
            return;
        }
        //3.1 获取地标对象
        CLPlacemark *pm = placemarks.firstObject;
        // 大头针模型,能设置大头针的显示位置及标题子标题
        userLocation.title = pm.administrativeArea;
        //3.3 设置子标题 详细地址
        userLocation.subtitle = pm.name;
    }];
}

设置以用户位置为中心点
在mapView上创建一个按钮,点击按钮执行下面代码

//1. 获取用户定位的中心点经纬度
CLLocationCoordinate2D center = self.mapView.userLocation.location.coordinate;
//2. 显示跨度  1度 ~111千米
MKCoordinateSpan span = MKCoordinateSpanMake(0.021256, 0.016093);
//3. 动画设置地图的范围和中心点
[self.mapView setRegion: MKCoordinateRegionMake(center, span) animated:YES];
例子:放大缩小地图(每次放大、缩小一倍)
- (IBAction)zoomDaClick:(id)sender {
    CGFloat latitude = self.mapView.region.span.latitudeDelta * 0.5; //放大 * 2
    CGFloat longitude = self.mapView.region.span.longitudeDelta * 0.5;//放大 * 2
    //2. 设置 region,范围, 带动画
    [self.mapView setRegion: MKCoordinateRegionMake(self.mapView.region.center, MKCoordinateSpanMake(latitude, longitude)) animated:YES];
    //设置最大跨度
//    if (latitude > 140 || longitude > 140) {
//        return;
//    }
}

1、自定义系统类型大头针 (MKPinAnnotationView),使用的MKAnnotation大头针模型,只能改变大头针颜色,标题、子标题等属性
2、完全自定义大头针模型:创建一个模型类继承于NSObject,遵守协议 <MKAnnotation>,.h 选择设置以下属性,注意去掉readonly,其它属性如image可自定义

MKAnnotation 大头针模型类

(1)经纬度,必须设置的属性

@property (nonatomic) CLLocationCoordinate2D coordinate;

(2)标题、子标题

@property (nonatomic, copy, nullable) NSString *title;
@property (nonatomic, copy, nullable) NSString *subtitle;

(3)重新设置坐标

- (void)setCoordinate:(CLLocationCoordinate2D)newCoordinate;

大头针view显示类:MKPinAnnotationView 继承于 MKAnnotationView

1.MKAnnotationView :默认image属性没有赋值,可以完全自定义
(1)设置大头针可以被点击,用于显示附属视图、标题、子标题等,自定义时默认为NO,想要大头针被点击注意开启

@property (nonatomic) BOOL canShowCallout;

(2)设置左右边的附属视图

@property (strong, nonatomic, nullable) UIView *leftCalloutAccessoryView;
@property (strong, nonatomic, nullable) UIView *rightCalloutAccessoryView;

效果:


左右边的附属视图


(3)iOS 9新增,自定义详情/子标题,原来的子标题文字没了,变成了自定义控件

@property (nonatomic, strong, nullable) UIView *detailCalloutAccessoryView

效果:


自定义子标题

2.MKPinAnnotationView: image属性已被设置(圆帽形状),只能更改颜色

属性:

(1)设置大头针颜色

  • iOS9以前,只有3种颜色可选

    @property (nonatomic) MKPinAnnotationColor pinColor;

    MKPinAnnotationColor 颜色枚举:
    MKPinAnnotationColorRed
    MKPinAnnotationColorGreen
    MKPinAnnotationColorPurple

  • iOS9 以后方法,注意版本适配

    @property (strong, null_resettable) UIColor *pinTintColor( 9_0);

(2)是否开启动画掉落,默认为NO

@property (nonatomic) BOOL animatesDrop;
例子:在地图点击的点插上自定义大头针

系统自定义大头针

完全自定义大头针
#pragma mark - 自定义一个MyAnnotation大头针模型类继承于NSObject,写上 coordinate、title、subtitle、icon(完全自定义用)等属性

#pragma mark - 点击插自定义大头针,给大头针模型设置值,之前在viewDisLoad中已申请授权定位
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    // 获取点击的点
    CGPoint point = [[touches anyObject] locationInView:self.mapView];
    // point点换成地图上的经纬度的点
    CLLocationCoordinate2D coordinate = [self.mapView convertPoint:point toCoordinateFromView:self.mapView];
    // 创建一个自定义大头针对象
    MyAnnotation *annotion = [MyAnnotation new];
    // 大头针的位置就是点击的位置
    annotion.coordinate = coordinate;
    // 此处可以利用反地理编码来获取该坐标的地址详情
    annotion.title = @"优衣库";
    annotion.subtitle = @"三里屯";
//  annotion.icon = @"苍老师图片";  完全自定义时设置自定义大头针的图片
    // 将大头针添加到mapView上
    [self.mapView addAnnotation:annotion];
}

#pragma mark - 自定义系统样式大头针(与下面二选一),不同颜色的大头针方法(利用 MKPinAnnotationView)
// 设置自定义大头针的显示样式,大头针视图添加到地图之前调用,类似于cell的创建方式
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
    //判断是否是系统定位用的大头针
    if ([annotation isKindOfClass:[MKUserLocation class]]) {
        return nil;
    }
    static NSString *ID = @"annoView";
    //缓存池查找、创建一个MKPinAnnotationView类型的大头针
    MKPinAnnotationView *annoView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:ID];
    if (annoView == nil) {
        annoView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:ID];
        // 设置颜色
        annoView.pinColor = MKPinAnnotationColorRed;
        // 设置动画掉落
        annoView.animatesDrop = YES;
    }
    return annoView;
}

#pragma mark - 完全自定义样式大头针(与上面二选一),不同图片的大头针方法(利用 MKAnnotationView),也可以直接调用封装好的自定义大头针view,且不必给大头针view设置大头针模型,系统会自动调用view的set方法进行设置
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
    //判断是否是系统定位用的大头针
    if ([annotation isKindOfClass:[MKUserLocation class]]) {
        return nil;
    }
    static NSString *ID = @"annoView";

    //缓存池查找、创建一个完全自定义的大头针view
    MKAnnotationView *annoView = [mapView dequeueReusableAnnotationViewWithIdentifier:ID];
    if (annoView == nil) {
        annoView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:ID];
        // 使大头针可以被点击,可以查看附属视图
        annoView.canShowCallout = YES;
        // 设置左边的附属视图
        annoView.leftCalloutAccessoryView = [UISwitch new];
    }
    // 获取大头针模型,封装后就不用设置模型了
    MyAnnotation *anno = (MyAnnotation *)annotation;
    // 给大头针view设置模型数据(图像)
    annoView.image = [UIImage imageNamed:anno.icon];
    return annoView;
}

#pragma mark - 实现大头针掉落动画效果
//代理方法在添加大头针图像出现之前调用,参数views 为放置的大头针
- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray<MKAnnotationView *> *)views{
    for (MKAnnotationView *annoView in views) {
       // 不要将系统定位的大头针设置了动画效果
        if ([annoView.annotation isKindOfClass:[MKUserLocation class]]) {
            return;
        }
        // 记录要放置的大头针坐标的位置
        CGRect startFrame = annoView.frame;
        // 位置的 Y 改为0,用来掉落
        annoView.frame = CGRectMake(startFrame.origin.x, 0, startFrame.size.width, startFrame.size.height);
        // 执行动画掉落
        [UIView animateWithDuration:0.25 animations:^{
            annoView.frame = startFrame;
        }];
    }
}
封装一个自定义大头针view,类似于cell的封装,不同的是系统会自动调用大头针view的set方法

1.创建一个类方法,参数有mapview,用于缓存池查找

+ (instancetype)annotationViewWithMapView:(MKMapView *)mapView;

2.实现

+ (instancetype)annotationViewWithMapView:(MKMapView *)mapView{
    static NSString *ID = @"annoView";
    MyAnnotationView *annoView = (MyAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:ID];
    if (annoView == nil) {
        annoView = [[MyAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:ID];
        annoView.canShowCallout = YES;
        annoView.leftCalloutAccessoryView = [UISwitch new];
    }
    return annoView;
}

#pragma mark 系统会自动调用大头针view的 set 方法,一旦重写必须调用父类方法,不然会没有数据
- (void)setAnnotation:(MyAnnotation *)annotation{
    //1. 调用 super 设置模型
    [super setAnnotation:annotation];
    //2. 设置图像
    self.image = [UIImage imageNamed:annotation.icon];
}

导航和画线

一、打开系统地图进行导航(modal出新的界面,跳到系统的地图界面)

步骤:
1、创建地理编码对象,调用正地理编码方法,获取 CLPlacemark 地标对象
2、构造方法用上面参数创建一个 MKPlacemark 对象
3、构造方法用上面参数创建一个 MKMapItem 对象,作为终点位置

调用open类方法,打开系统自带地图从用户位置导航到指定的地点

MKMapItem 就是地图上的一个点

+ (BOOL)openMapsWithItems:(NSArray<MKMapItem *> *)mapItems launchOptions:(nullable NSDictionary<NSString *, id> *)launchOptions;

参数:

mapItems:要导航到的点
launchOptions:导航参数,字典,KEY值如下(注意整型的包装):
1、设置导航模式
MKLaunchOptionsDirectionsModeKe
枚举:
MKLaunchOptionsDirectionsModeDriving     开车
MKLaunchOptionsDirectionsModeWalking     走路
MKLaunchOptionsDirectionsModeTransit     公交

2、设置地图类型
MKLaunchOptionsMapTypeKey
枚举:
MKMapTypeStandard :标准模式
MKMapTypeSatellite :卫星模式
MKMapTypeHybrid  :混合模式

3、是否显示交通状况,BOOLMKLaunchOptionsShowsTrafficKey
4、中心点坐标,CLLocationCoordinate2D类型
MKLaunchOptionsMapCenterKey
5、地图显示跨度,MKCoordinateSpan 类型
MKLaunchOptionsMapSpanKey
63D地图效果,MKMapCamera类型,iOS7及以后可用
MKLaunchOptionsCameraKey
例子:点击按钮后跳到系统地图导航到指定地点
- (IBAction)navigateClick:(id)sender {
    //1. 创建CLGeocoder对象
    CLGeocoder *geocoder = [CLGeocoder new];
    //2. 调用地理编码方法
    [geocoder geocodeAddressString:self.destinationTF.text completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
        //3 防错处理
        if (placemarks.count == 0 || error) {
            return;
        }
        //4. 获取地标对象 暂取最后一个
        CLPlacemark *pm = placemarks.lastObject;
        //5. 创建MKPlacemark对象
        MKPlacemark *mkpm = [[MKPlacemark alloc] initWithPlacemark:pm];
        //6. 创建一个MKMapItem
        MKMapItem *destinationItem = [[MKMapItem alloc] initWithPlacemark:mkpm];
        //7. 调用open类方法, 打开导航
        NSDictionary *options = @{MKLaunchOptionsDirectionsModeKey : MKLaunchOptionsDirectionsModeDriving, MKLaunchOptionsMapTypeKey : @(MKMapTypeHybrid), MKLaunchOptionsShowsTrafficKey : @(YES)};
        [MKMapItem openMapsWithItems:@[destinationItem] launchOptions:options];
    }];
}

二、地图画线,在mapView中,iOS8以后无法在模拟器运行

步骤:(就是各种转换,步骤多的看着就恶心,可以直接看下面代码)
1、创建地理编码对象,调用正地理编码方法,获取 CLPlacemark 地标对象
2、构造方法用上面参数创建一个 MKPlacemark 对象
3、构造方法用上面参数创建两个个 MKMapItem 对象,作为起点和终点位置
4、创建方向请求对象( MKDirectionsRequest ),分别设置起点和终点( source、 destination)
5、创建方向对象( MKDirections ),构造方法利用上面的请求对象
6、用方向对象调用计算两点之间的路线方法,回调获取 MKDirectionsResponse 类型响应
7、从响应对象中获取一组路线对象( MKRoute)路线对象,有些属性天朝用不了,如暴风雪路线
8、遍历该组路线对象,取出每个折线( polyline属性 MKPolyline类型)分别渲染到mapView上(通过mapView的 addOverlay:方法)
9、在mapView代理方法中创建地图渲染物
(1)创建折线渲染物对象( MKPolylineRenderer ),构造方法利用代理的 overlay 参数
(2)设置线条颜色(必须设置,否则不显示 fillColor 或 strokeColor )
(3)返回渲染对象

例子:

地图画线
#pragma mark 导航按钮点击
- (IBAction)navigateClick:(id)sender {
    // 回收键盘
    [self.view endEditing:YES];
    //1. 创建CLGeocoder对象
    CLGeocoder *geocoder = [CLGeocoder new];
    //2. 调用地理编码方法
    [geocoder geocodeAddressString:self.destinationTF.text completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
        //3 防错处理
        if (placemarks.count == 0 || error) {
            return;
        }
        //4. 获取地表对象 暂取最后一个
        CLPlacemark *pm = placemarks.lastObject;
        //5. 创建MKPlacemark对象
        MKPlacemark *mkpm = [[MKPlacemark alloc] initWithPlacemark:pm];

        //6.1 创建一个终点MKMapItem
        MKMapItem *destinationItem = [[MKMapItem alloc] initWithPlacemark:mkpm];
        //6.2 创建一个起点MKMapItem(当前位置)
        MKMapItem *souceItem = [MKMapItem mapItemForCurrentLocation];

        //7. 创建一个方向请求对象,分别设置起点和终点
        MKDirectionsRequest *request = [MKDirectionsRequest new];
        //7.1 设置终点
        request.destination = destinationItem;
        //7.2 设置起点
        request.source = souceItem;

        //8. 创建方向对象,利用请求对象
        MKDirections *direction = [[MKDirections alloc] initWithRequest:request];
        //9. 调用请求对象的 计算路径方法
        [direction calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse * _Nullable response, NSError * _Nullable error) {
            //10.1 防错处理
            if (response.routes.count == 0 || error) {
                NSLog(@"没有找到对应的路线");
                return ;
            }
            //10.2 从返回的response中获取一组 MKRoute 路线对象
            for (MKRoute *route in response.routes) {
                //11. 从路线对象中获取折线对象
                MKPolyline *polyline = route.polyline;
                //12. 将折线对象通过渲染方式添加到地图上,注意在渲染的代理方法中为折线设置颜色
                [self.mapView addOverlay:polyline];
            }
        }];
    }];
}

#pragma mark - mapView的代理方法,当给地图添加了遮盖物的时候就会用此方法,设置一个渲染物对象添加到地图上
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay{
    //1. 创建一个折线渲染物对象(MKOverlayRenderer的子类)
    MKPolylineRenderer *polyline = [[MKPolylineRenderer alloc] initWithOverlay:overlay];
    //2. 设置线条颜色,必须设置,否则看不见
    polyline.fillColor = [UIColor redColor];
    //polyline.strokeColor = [UIColor blueColor];
    //3. 设置线条宽度
    polyline.lineWidth = 10;
    return polyline;
}


MapKit开发进阶——使用导航和附近兴趣点检索

iOS中的mapKit框架对国际化的支持非常出色。在前些篇博客中,对这个地图框架的基础用法和标注与覆盖物的添加进行了详细的介绍,这篇博客将介绍两个更加实用的功能的开发:线路导航与兴趣点搜索。前几篇博客的链接如下:

地图基础用法详解:http://my.oschina.net/u/2340880/blog/415360

添加大头针与自定义标注:http://my.oschina.net/u/2340880/blog/415441

添加地图覆盖物:http://my.oschina.net/u/2340880/blog/415611

一、线路导航

1、从几个类的关系说起

(1)MKPlacemark

一个地点信息类,如下:

1
2
3
4
5
6
7
@interface MKPlacemark : CLPlacemark <MKAnnotation>
//初始化方法,通过给定一个经纬度和地点信息字典
- (instancetype)initWithCoordinate:(CLLocationCoordinate2D)coordinate
                  addressDictionary:(NSDictionary *)addressDictionary;
//国家编码
@property (nonatomic, readonly) NSString *countryCode;
@end

(2)MKMapItem

地点节点类,包含此节点的许多地点信息,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@interface MKMapItem : NSObject
//当前节点的地点信息对象
@property (nonatomic, readonly) MKPlacemark *placemark;
//是否是当前位置
@property (nonatomic, readonly)  BOOL  isCurrentLocation;
//节点名称
@property (nonatomic, copy) NSString *name;
//电话号码
@property (nonatomic, copy) NSString *phoneNumber;
//网址
@property (nonatomic, strong) NSURL *url;
//将当前位置创建为节点
+ (MKMapItem *)mapItemForCurrentLocation;
//由一个位置信息创建节点
- (instancetype)initWithPlacemark:(MKPlacemark *)placemark;
 
@end

(3)MKDirectionsRequest

导航请求类

1
2
3
4
5
6
7
8
9
@interface MKDirectionsRequest : NSObject
//起点节点
- (MKMapItem *)source NS_AVAILABLE(10_9, 6_0);
- ( void )setSource:(MKMapItem *)source NS_AVAILABLE(10_9, 7_0);
//目的地节点
- (MKMapItem *)destination NS_AVAILABLE(10_9, 6_0);
- ( void )setDestination:(MKMapItem *)destination NS_AVAILABLE(10_9, 7_0);
 
@end

这个类还有一些扩展的设置属性:

@property (nonatomicMKDirectionsTransportType transportType;

设置路线检索类型,枚举如下:

1
2
3
4
5
typedef  NS_OPTIONS(NSUInteger, MKDirectionsTransportType) {
     MKDirectionsTransportTypeAutomobile     = 1 << 0, //适合驾车时导航
     MKDirectionsTransportTypeWalking        = 1 << 1, //适合步行时导航
     MKDirectionsTransportTypeAny            = 0x0FFFFFFF //任何情况
};

@property (nonatomicBOOL requestsAlternateRoutes;

设置是否搜索多条线路

@property (nonatomiccopyNSDate *departureDate;

设置出发日期

@property (nonatomiccopyNSDate *arrivalDate;

设置到达日期


(4)MKDirections

从apple服务器获取数据的连接类

1
2
3
4
5
6
7
8
9
10
11
12
@interface MKDirections : NSObject
//初始化方法
- (instancetype)initWithRequest:(MKDirectionsRequest *)request NS_DESIGNATED_INITIALIZER;
//开始计算线路信息
- ( void )calculateDirectionsWithCompletionHandler:(MKDirectionsHandler)completionHandler;
//开始计算时间信息
- ( void )calculateETAWithCompletionHandler:(MKETAHandler)completionHandler;
//取消
- ( void )cancel;
//是否正在计算
@property (nonatomic, readonly, getter=isCalculating)  BOOL  calculating;
@end

(5)MKDirectionsResponse

线路信息结果类

1
2
3
4
5
@interface MKDirectionsResponse : NSObject
@property (nonatomic, readonly) MKMapItem *source; //起点
@property (nonatomic, readonly) MKMapItem *destination; //终点
@property (nonatomic, readonly) NSArray *routes;  //线路规划数组
@end

(6)MKETResponse

时间信息结果类

1
2
3
4
5
6
@interface MKETAResponse : NSObject
@property (nonatomic, readonly) MKMapItem *source; //起点
@property (nonatomic, readonly) MKMapItem *destination; //终点
@property (nonatomic, readonly) NSTimeInterval expectedTravelTime; //耗时
 
@end

(7)MKRoute

线路信息类,导航的线路结果是这个类型的对象

1
2
3
4
5
6
7
8
9
10
11
12
13
@interface MKRoute : NSObject
 
@property (nonatomic, readonly) NSString *name;  //线路名称
@property (nonatomic, readonly) NSArray *advisoryNotices;  //注意事项
@property (nonatomic, readonly) CLLocationDistance distance;  //距离
@property (nonatomic, readonly) NSTimeInterval expectedTravelTime; //耗时
@property (nonatomic, readonly) MKDirectionsTransportType transportType;  //检索的类型
 
@property (nonatomic, readonly) MKPolyline *polyline;  // 线路覆盖物
 
@property (nonatomic, readonly) NSArray *steps;  // 线路详情数组
 
@end

(8)MKRouteStep

线路详情信息类,线路中每一步的信息都是这个类的对象

1
2
3
4
5
6
7
8
9
10
11
12
@interface MKRouteStep : NSObject
 
@property (nonatomic, readonly) NSString *instructions;  // 节点信息
@property (nonatomic, readonly) NSString *notice;  // 注意事项
 
@property (nonatomic, readonly) MKPolyline *polyline;  //线路覆盖物
 
@property (nonatomic, readonly) CLLocationDistance distance;  // 距离
 
@property (nonatomic, readonly) MKDirectionsTransportType transportType;  // 导航类型
 
@end

看到上面如此多的类,你可能会觉得一头雾水,那么不用着急,类虽然繁杂,但他们之间的逻辑非常清晰,下面就通过一个例子来进行线路导航。

2、进行线路导航
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
- ( void )viewDidLoad {
     [super viewDidLoad];
     //地图初始化设置
     mapView =[[MKMapView alloc]initWithFrame:self.view.frame];
     mapView.region=MKCoordinateRegionMake(CLLocationCoordinate2DMake(39.26, 116.3), MKCoordinateSpanMake(5, 5));
     mapView.mapType=MKMapTypeStandard;
     mapView.delegate=self;
     [self.view addSubview:mapView];
     
     //导航设置
     CLLocationCoordinate2D fromcoor=CLLocationCoordinate2DMake(39.26, 116.3);
     CLLocationCoordinate2D tocoor = CLLocationCoordinate2DMake(33.33, 113.33);
     //创建出发点和目的点信息
     MKPlacemark *fromPlace = [[MKPlacemark alloc] initWithCoordinate:fromcoor
                                                        addressDictionary:nil];
     MKPlacemark *toPlace = [[MKPlacemark alloc]initWithCoordinate:tocoor addressDictionary:nil];
     //创建出发节点和目的地节点
     MKMapItem * fromItem = [[MKMapItem alloc]initWithPlacemark:fromPlace];
     MKMapItem * toItem = [[MKMapItem alloc]initWithPlacemark:toPlace];
     //初始化导航搜索请求
     MKDirectionsRequest *request = [[MKDirectionsRequest alloc]init];
     request.source=fromItem;
     request.destination=toItem;
     request.requestsAlternateRoutes=YES;
     //初始化请求检索
     MKDirections *directions = [[MKDirections alloc]initWithRequest:request];
     //开始检索,结果会返回在block中
     [directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) {
         if  (error) {
             NSLog(@ "error:%@" ,error);
         } else {
             //提取导航线路结果中的一条线路
             MKRoute *route =response.routes[0];
             //将线路中的每一步详情提取出来
             NSArray * stepArray = [NSArray arrayWithArray:route.steps];
             //进行遍历
             for  ( int  i=0; i<stepArray.count; i++) {
                 //线路的详情节点
                 MKRouteStep * step = stepArray[i];
                 //在此节点处添加一个大头针
                 MKPointAnnotation * point = [[MKPointAnnotation alloc]init];
                 point.coordinate=step.polyline.coordinate;
                 point.title=step.instructions;
                 point.subtitle=step.notice;
                 [mapView addAnnotation:point];
                 //将此段线路添加到地图上
                 [mapView addOverlay:step.polyline];
             }
         }
     }];  
}
//地图覆盖物的代理方法
-(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay{
     MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithPolyline:overlay];
     
     renderer.strokeColor = [UIColor redColor];
     
     renderer.lineWidth = 4.0;
     
     return   renderer;
}
//标注的代理方法
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
     MKPinAnnotationView * view= [[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:@ "anno" ];
     view.canShowCallout=YES;
     return  view;
}

效果如下:


二、附近兴趣点检索

兴趣点检索的逻辑和导航线路检索的逻辑相似,直接通过代码来演示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
     //创建一个位置信息对象,第一个参数为经纬度,第二个为纬度检索范围,单位为米,第三个为经度检索范围,单位为米
     MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(tocoor, 5000, 5000);
     //初始化一个检索请求对象
     MKLocalSearchRequest * req = [[MKLocalSearchRequest alloc]init];
     //设置检索参数
     req.region=region;
     //兴趣点关键字
     req.naturalLanguageQuery=@ "hotal" ;
     //初始化检索
     MKLocalSearch * ser = [[MKLocalSearch alloc]initWithRequest:req];
     //开始检索,结果返回在block中
     [ser startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) {
         //兴趣点节点数组
         NSArray * array = [NSArray arrayWithArray:response.mapItems];
         for  ( int  i=0; i<array.count; i++) {
             MKMapItem * item=array[i];
             MKPointAnnotation * point = [[MKPointAnnotation alloc]init];
             point.title=item.name;
             point.subtitle=item.phoneNumber;
             point.coordinate=item.placemark.coordinate;
             [mapView addAnnotation:point];
         }
     }];

效果如下:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值