地图(二)-MapKit

作者: fran_cis_ | 来源:发表于2017-05-21 20:22 被阅读67次

    一、地图开发介绍

    从iOS6.0开始地图数据不再由谷歌驱动,而是改用自家地图,当然在国内它的数据是由高德地图提供的。

    在iOS中进行地图开发主要有三种方式:

    • 利用MapKit框架进行地图开发,利用这种方式可以对地图进行精准的控制
    • 调用苹果官方自带的地图应用,主要用于一些简单的地图应用,无法精确控制
    • 使用第三方地图开发SDK库

    用得最多的还是MapKit,所以这节就只讲MapKit的使用。

    二、MapKit核心类

    1. 属性:

    MapKit的核心类为地图展示控件MKMapView,以下是常用的属性、对象方法以及代理方法。

    /* 用户位置跟踪 */
    @property (nonatomic) BOOL showsUserLocation;/*< 是否在地图上标注用户位置 */
    @property (nonatomic, readonly) MKUserLocation *userLocation;/*< 用户位置 */
    @property (nonatomic) MKUserTrackingMode userTrackingMode;/*< 用户跟踪类型 */
    typedef NS_ENUM(NSInteger, MKUserTrackingMode) {
        MKUserTrackingModeNone = 0, /*< 不跟踪 */
        MKUserTrackingModeFollow, /*< 跟踪 */
        MKUserTrackingModeFollowWithHeading,  /*< 导航跟踪 */
    };
    /* 设置地图配置项 */
    @property (nonatomic) MKMapType mapType;/*< 地图类型 */
    @property (nonatomic, readonly) NSArray *annotations;/*< 大头针数组 */
    typedef NS_ENUM(NSUInteger, MKMapType) {
        MKMapTypeStandard = 0,/*< 标准地图 */
        MKMapTypeSatellite,/*< 卫星地图 */
        MKMapTypeHybrid,/*< 混合模式(标准+卫星) */
        MKMapTypeSatelliteFlyover,/*< 3D立体卫星(iOS9.0) */
        MKMapTypeHybridFlyover,/*< 3D立体混合(iOS9.0) */
    }
    /* 设置地图控制项 */
    @property (nonatomic) BOOL zoomEnabled;/*< 是否可以缩放 */
    @property (nonatomic) BOOL scrollEnabled;/*< 是否可以滚动 */
    @property (nonatomic) BOOL rotateEnabled;/*< 是否可以旋转 */
    @property (nonatomic) BOOL pitchEnabled;/*< 是否显示3D视角 */
    /* 设置地图显示项 */
    @property (nonatomic) BOOL showsBuildings;/*< 是否显示建筑物,只影响标准地图 */
    @property (nonatomic) BOOL showsTraffic;/*< 是否显示交通,iOS9 */
    @property (nonatomic) BOOL showsCompass;/*< 是否显示指南针,iOS9 */
    @property (nonatomic) BOOL showsScale;/*< 是否显示比例尺,iOS9 */
    

    2. 对象方法:

    /* 添加大头针 */
    - (void)addAnnotation:(id <MKAnnotation>)annotation;
    - (void)addAnnotations:(NSArray<id<MKAnnotation>> *)annotations;
    /* 删除大头针 */
    - (void)removeAnnotation:(id <MKAnnotation>)annotation;
    - (void)removeAnnotations:(NSArray<id<MKAnnotation>> *)annotations;
    /* 选中大头针与取消选中大头针 */
    - (void)selectAnnotation:(id <MKAnnotation>)annotation 
                    animated:(BOOL)animated;
    - (void)deselectAnnotation:(id <MKAnnotation>)annotation 
                      animated:(BOOL)animated;
    /* 获取大头针视图 */
    - (MKAnnotationView *)viewForAnnotation:(id <MKAnnotation>)annotation;
    /* 从缓冲池中取出大头针视图控件 */
    - (MKAnnotationView *)dequeueReusableAnnotationViewWithIdentifier:(NSString *)identifier;
    /* 设置显示区域以及地图中心坐标 */
    - (void)setRegion:(MKCoordinateRegion)region 
             animated:(BOOL)animated;
    - (void)setCenterCoordinate:(CLLocationCoordinate2D)coordinate 
                       animated:(BOOL)animated;
    /* 经纬度坐标转UIKit坐标,UIKit坐标转经纬度坐标 */
    - (CGPoint)convertCoordinate:(CLLocationCoordinate2D)coordinate 
                   toPointToView:(UIView *)view;
    - (CLLocationCoordinate2D)convertPoint:(CGPoint)point 
                      toCoordinateFromView:(UIView *)view;
    

    3. 常用代理方法MKMapViewDelegate

    /* 地图加载完成会调用 */
    - (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView;
    /* 地图加载失败会调用 */
    - (void)mapViewDidFailLoadingMap:(MKMapView *)mapView withError:(NSError *)error;
    /* 用户位置发生改变会调用 */
    - (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation;
    /* 显示区域改变会调用 */
    - (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated;
    /* 点击选中大头针时会调用 */
    - (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view;
    /* 取消选中大头针时会调用 */
    - (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view;
    /* 显示地图上的大头针,功能类似于UITableView的tableView:cellForRowAtIndexPath:方法 */
    - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation;
    

    三、MapKit使用

    1. 初始化地图展示控件MKMapView

    #import "ViewController.h"
    #import <MapKit/MapKit.h>
    
    @interface ViewController ()<MKMapViewDelegate>
    @property (nonatomic ,strong) MKMapView *mapView;
    @property (nonatomic, strong) CLLocationManager *locationM;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        //获取定位服务授权
        [self requestUserLocationAuthor];
        //初始化MKMapView
        [self initMapView];
    }
    - (void)requestUserLocationAuthor{
        //如果没有获得定位授权,获取定位授权请求
        self.locationM = [[CLLocationManager alloc] init];
        if ([CLLocationManager locationServicesEnabled]) {
            if ([CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorizedWhenInUse) {
                [self.locationM requestWhenInUseAuthorization];
            }
        }
    }
    - (void)initMapView{
        CGFloat x = 0;
        CGFloat y = 20;
        CGFloat width = self.view.frame.size.width;
        CGFloat height = self.view.frame.size.height;
        //创建MKMapView对象
        MKMapView *mapView = [[MKMapView alloc] initWithFrame:CGRectMake(x, y, width, height)];
        //设置地图类型
        mapView.mapType = MKMapTypeStandard;
        //设置用户跟踪模式
        mapView.userTrackingMode = MKUserTrackingModeFollow;
        //显示交通路线
        mapView.showsTraffic = YES;
        mapView.delegate = self;
        [self.view addSubview:mapView];
        self.mapView = mapView;
    }
    #pragma mark - MKMapViewDelegate
    //跟踪到用户位置时会调用该方法
    - (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{
        //创建编码对象
        CLGeocoder *geocoder=[[CLGeocoder alloc]init];
        //反地理编码
        [geocoder reverseGeocodeLocation:userLocation.location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
            if (error!=nil || placemarks.count==0) {
                return ;
            }
            //获取地标
            CLPlacemark *placemark=[placemarks firstObject];
            //设置标题
            userLocation.title=placemark.locality;
            //设置子标题
            userLocation.subtitle=placemark.name;
    
        }];
        
    }
    

    2. 添加大头针

    在iOS开发中经常会标记某个位置,需要使用地图标注,也就是大家俗称的“大头针”。只要一个 NSObject 类实现 MKAnnotation 协议就可以作为一个大头针,通常会重写协议中coordinate(标记位置)、title(标题)、subtitle(子标题)三个属性,然后在程序中创建大头针对象并调用 addAnnotation: 方法添加大头针即可(之所以iOS没有定义一个基类实现这个协议供开发者使用,多数原因应该是 MKAnnotation 是一个模型对象,对于多数应用模型会稍有不同,例如后面的内容中会给大头针模型对象添加其他属性)。

    KSTAnnotation.h

    #import <Foundation/Foundation.h>
    #import <MapKit/MapKit.h>
    
    @interface KSTAnnotation : NSObject<MKAnnotation>
    //经纬度
    @property (nonatomic) CLLocationCoordinate2D coordinate;
    //父标题
    @property (nonatomic, copy) NSString *title;
    //子标题
    @property (nonatomic, copy) NSString *subtitle;
    

    ViewController.m

    /*
     添加大头针
     */
    - (void)addAnnotationsToMapView{
        //创建大头针
        KSTAnnotation *annotation = [[KSTAnnotation alloc] init];
        annotation.coordinate = CLLocationCoordinate2DMake(28.725925, 115.836062);
        annotation.title = @"父标题";
        annotation.subtitle = @"子标题";
        //添加大头针
        [self.mapView addAnnotation:annotation];
        
        //创建大头针
        KSTAnnotation *annotation1 = [[KSTAnnotation alloc] init];
        annotation1.coordinate = CLLocationCoordinate2DMake(28.716342, 115.825464);
        annotation1.title = @"francis";
        annotation1.subtitle = @"kst";
        //添加大头针
        [self.mapView addAnnotation:annotation1];
    }
    

    3.自定义大头针

    在一些应用中系统默认的大头针样式可能无法满足实际的需求,此时就需要修改大头针视图默认样式。根据前面 MapKit 的代理方法不难发现 - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation;方法可以返回一个大头针视图,只要实现这个方法并在这个方法中定义一个大头针视图 MKAnnotationView 对象并设置相关属性就可以改变默认大头针的样式

    需要注意:

    a.这个代理方法的调用时机:每当有大头针显示到系统可视界面中时就会调用此方法返回一个大头针视图放到界面中,同时当前系统位置标注(也就是地图中蓝色的位置点)也是一个大头针,也会调用此方法,因此处理大头针视图时需要区别对待。

    b.类似于UITableView的代理方法,此方法调用频繁,开发过程中需要重复利用MapKit的缓存池将大头针视图缓存起来重复利用。

    c.自定义大头针默认情况下不允许交互,如果交互需要设置canShowCallout=YES

    d.如果代理方法返回nil则会使用默认大头针视图,需要根据情况设置。

    下面以一个示例进行大头针视图设置,这里设置了大头针的图片、弹出视图、偏移量等信息。

    KSTAnnotation.h

    #import <Foundation/Foundation.h>
    #import <MapKit/MapKit.h>
    
    @interface KSTAnnotation : NSObject<MKAnnotation>
    //经纬度
    @property (nonatomic) CLLocationCoordinate2D coordinate;
    //父标题
    @property (nonatomic, copy) NSString *title;
    //子标题
    @property (nonatomic, copy) NSString *subtitle;
    //自定义一个图片属性在创建大头针视图时使用
    @property (nonatomic, strong) UIImage *icon;
    

    ViewController.m

    /*
     添加大头针
     */
    - (void)addAnnotationsToMapView{
        //创建大头针
        KSTAnnotation *annotation = [[KSTAnnotation alloc] init];
        annotation.coordinate = CLLocationCoordinate2DMake(28.725925, 115.836062);
        annotation.title = @"父标题";
        annotation.subtitle = @"子标题";
        annotation.icon = [UIImage imageNamed:@"火影"];//大头针icon, 不要忘记
        //添加大头针
        [self.mapView addAnnotation:annotation];
        
        //创建大头针
        KSTAnnotation *annotation1 = [[KSTAnnotation alloc] init];
        annotation1.coordinate = CLLocationCoordinate2DMake(28.716342, 115.825464);
        annotation1.title = @"francis";
        annotation1.subtitle = @"kst";
        annotation1.icon = [UIImage imageNamed:@"myIcon"];//大头针icon, 不要忘记
        //添加大头针
        [self.mapView addAnnotation:annotation1];
    }
    
    /* 每当大头针显示在可视界面上时,就会调用该方法,用户位置的蓝色点也是个大头针,也会调用 */
    - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
    {
        if ([annotation isKindOfClass:[KSTAnnotation class]]) {
            KSTAnnotation *annotationKST = (KSTAnnotation *)annotation;
            //类似于UITableViewCell的重用机制,大头针视图也有重用机制
            static NSString *key = @"AnnotationIdentifier";
            MKAnnotationView *view = [self.mapView dequeueReusableAnnotationViewWithIdentifier:key];
            if (!view) {
                view = [[MKAnnotationView alloc] initWithAnnotation:annotation
                                                    reuseIdentifier:key];
            }
            //设置大头针数据
            view.annotation = annotation;
            //自定义大头针默认是NO,表示不能弹出视图,这里让大头针可以点击弹出视图
            view.canShowCallout = YES;
            view.calloutOffset=CGPointMake(0, 1);//定义详情视图偏移量
            //设置大头针图标
            view.image = annotationKST.icon;//不要忘记
            //设置弹出视图的左边视图
            UIImage *leftImage = [UIImage imageNamed:@"火影"];
            UIImageView *leftView = [[UIImageView alloc] initWithImage: leftImage];
            leftView.bounds = CGRectMake(0, 0, 50, 50);
            view.leftCalloutAccessoryView = leftView;
            //设置弹出视图的右边视图
            UIImage *rightImage = [UIImage imageNamed:@"myIcon"];
            UIImageView *rightView = [[UIImageView alloc] initWithImage: rightImage];
            rightView.bounds = CGRectMake(0, 0, 50, 50);
            view.rightCalloutAccessoryView = rightView;
            return view;
        }
        //返回nil,表示显示默认样式
        return nil;
    }
    

    相关文章

      网友评论

        本文标题:地图(二)-MapKit

        本文链接:https://www.haomeiwen.com/subject/blgmxxtx.html