iOS 模块详解—「CoreLocation、MapKit、BaiduMap、GaodeMap」.md

阅读 37
收藏 1
2017-09-26
原文链接:mp.weixin.qq.com


你我之间定位和航行,至关重要 ~

引导


实际开发中涉及到定位和地图相关功能需求,你可能会选择三方高德地图、百度地图都是不错的。当然最基础的则是系统中自带的地图,了解基础框架内部实现有助于我们更好的实现地图需求。系统框架:(CoreLocation 定位框架)、(MapKit 地图框架),三方框架:(BaiduMap 百度地图)、(GaodeMap 高德地图)。

CoreLocation 框架


CoreLocation 基础
  • CoreLocation 框架(CoreLocation.framework)是SDK中一个提供设配位置的框架,可用于定位设备当前的经纬度,通过该框架,应用程序可通过附近的GPS (定位耗电量最大,速度最慢,但是精度最高)、蜂窝基站、WIFI信号计算用户位置(精准度递减排序)。

CoreLocation 功能
  • 【地理定位】:获取用户所以在区域,得到相应的经纬度或者海拔等一些地理信息。

  • 【(反) 地理编码】:前者:根据详细的地址转换为经纬度信息。后者 (反) :根据经纬度信息转换成具体地址。

  • 【区域监听】:指定一个区域,当用户进入或者离开这个区域,我们都可以监听到对应信息。

  • 【一般MapKit和一起使用】,MapKit能进行定位也能展示地图。

CoreLocation 相关类
/**
 CoreLocation 框架相关类
 
 #import <CoreLocation/CLAvailability.h> //
 #import <CoreLocation/CLErrorDomain.h> //
 #import <CoreLocation/CLError.h> //
 #import <CoreLocation/CLRegion.h> // 该对象代表一个区域。一般程序不会直接使用该类,而是使用它的两个子类,
 #import <CoreLocation/CLCircularRegion.h> // 即CLCircularRegion(圆形区域)
 #import <CoreLocation/CLBeaconRegion.h> // CLBeaconRegion(蓝牙信号区);
 #import <CoreLocation/CLHeading.h> // 该对象代表设备的移动方向;
 #import <CoreLocation/CLLocation.h> // 该对象代表位置。该对象包含了当前设备的经度、纬度、高度、速度、路线等信息,还包含了该定位信息的水平精确度、垂直精确度以及时间戳信息;
 #import <CoreLocation/CLLocationManager.h> // 定位管理器类;
 #import <CoreLocation/CLLocationManagerDelegate.h> // 该协议代表定位管理器的delegate协议。实现该协议的对象可负责处理CLLocationManager的定位事件;
 #import <CoreLocation/CLLocationManager+CLVisitExtensions.h> //
 #import <CoreLocation/CLPlacemark.h> // 地标对象
 #import <CoreLocation/CLGeocoder.h> // 地理编码器
 #import <CoreLocation/CLVisit.h> // 
 
 
 CoreLocation 框架还涉及一个 <CLLocationCoordinate2D> 结构体变量,该结构体变量包含经度、纬度两个值,
              其中CLLocation对象的coordinate属性就是一个CLLocationCoordinate2D结构体变量。
 
 CoreLocation 框架还涉及一个 NSArray<CLPlacemark *> 地标对象,该类中常用API有 location:对应的位置对象、name : 地址全称、locality : 城市,
              其 CLPlacemark 在 NSArray 中按相关性进行排序(取第一个最优位置),实际应用中是通过 tableView 或其他控件给用户弹一个框,用户自己选择。
 
 WechatPublic-Codeidea
*/
CoreLocation 核心类属性方法

CoreLocation 框架下实现定位功能的核心类是 CLLocationManager.h,下面是这个类的常用属性和方法。

CoreLocation核心类:CLLocationManager.h《WechatPublic-Codeidea》
 - 【类方法】
 
    /* 返回用户是否启用定位服务 */
    + (BOOL)locationServicesEnabled __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_4_0);

    /* 定位服务授权状态,返回枚举类型 */
    + (CLAuthorizationStatus)authorizationStatus __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_4_2);

    typedef NS_ENUM(int, CLAuthorizationStatus){
        kCLAuthorizationStatusNotDetermined = 0, /* 用户尚未决定是否启用定位服务 */
        kCLAuthorizationStatusRestricted, /* 没有获得用户授权, 系统预留字段 */
        kCLAuthorizationStatusDenied, /* 用户禁止使用定位或者定位服务处于关闭状态 */
        kCLAuthorizationStatusAuthorizedAlways, /* 前台、后台定位授权 */
        kCLAuthorizationStatusAuthorizedWhenInUse, /* 前台定位授权 */
    };


 - 【对象属性】

    // 设置过滤距离, 位置信息更新最小距离 By default, kCLDistanceFilterNone is used
    @property(assign, nonatomic) CLLocationDistance distanceFilter;

    // 设置定位精度, 枚举类型
    @property(assign, nonatomic) CLLocationAccuracy desiredAccuracy;

    extern const CLLocationAccuracy kCLLocationAccuracyBestForNavigation // 最适合导航__OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_4_0);
    extern const CLLocationAccuracy kCLLocationAccuracyBest; // 精确度最佳
    extern const CLLocationAccuracy kCLLocationAccuracyNearestTenMeters; // 精确度10米以内
    extern const CLLocationAccuracy kCLLocationAccuracyHundredMeters; // 精确度100米以内
    extern const CLLocationAccuracy kCLLocationAccuracyKilometer; // 精确度1000米以内
    extern const CLLocationAccuracy kCLLocationAccuracyThreeKilometers; // 精确度3000米以内
   【NOTE】:定位精度越高,耗电越多且定位时间越长,可根据实际情况而定。

 - 【对象方法】

    #pragma mark - 定位追踪
    /* 开始定位追踪 */
    - (void)startUpdatingLocation __TVOS_PROHIBITED;
    /* 停止定位追踪 */
    -(void)stopUpdatingLocation;

    #pragma mark - 导航追踪
    /* 开始导航方向追踪 */
    - (void)startUpdatingHeading __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_3_0) __TVOS_PROHIBITED __WATCHOS_PROHIBITED;
    /* 停止导航方向追踪 */
    -(void)stopUpdatingHeading;

    #pragma mark - 区域定位追踪
    /* 开始对某个区域进行定位追踪 */
    - (void)startMonitoringForRegion:(CLRegion *)region __OSX_AVAILABLE_STARTING(__MAC_10_8,__IPHONE_5_0) __TVOS_PROHIBITED __WATCHOS_PROHIBITED;
    /* 停止对某个区域进行定位追踪 */
    - (void)stopMonitoringForRegion:(CLRegion *)region __OSX_AVAILABLE_STARTING(__MAC_10_8,__IPHONE_4_0) __TVOS_PROHIBITED __WATCHOS_PROHIBITED;

    #pragma mark - 授权请求
    /* 请求获得应用前台定位授权 */
    - (void)requestWhenInUseAuthorization __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_8_0);
    /* 请求获得应用前后台定位授权 */
    - (void)requestAlwaysAuthorization __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_8_0) __TVOS_PROHIBITED;

 - 【代理方法】

    /* 位置发生改变后调用,第一次定位也会调用 */
    -(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations;
    /* 导航方向发生变化后调用 */
    -(void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading;
    /* 进入某个区域后调用 */
    -(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region;
    /* 走出某个区域后调用 */
    -(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region;
    /* 当用户授权状态发生变化时调用 */
    -(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status;
CoreLocation 基本使用

CoreLocation 定位 iOS8.0 之前

【步骤】:1、导入CoreLocation框架对应的主头文件; #import <CoreLocation/CoreLocation.h> 2、创建 CLLocationManager 对象并设置代理; 采用懒加载3、调用方法 startUpdatingLocation 开启定位器,更新用户位置信息;如果不用时必须停止服务就用  stopUpdatingLocation。4、在对应的代理方法(didUpdateLocations:) 中获取位置信息;

【后台定位】:1、在前台定位基础上, 勾选后台模式(Background Modes) Location updates 2、NOTE:定位精度越高,耗电越多且定位时间越长,可根据实际情况而定。

CoreLocation 定位 iOS8.0 之后, iOS9.0 之后

iOS8.0 对定位进行了一些修改,其中包括定位授权的方法,CLLocationManager 增加了如下两个方法:// 请求前后台定位授权- (void)requestAlwaysAuthorization __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_8_0);

// 请求前台定位授权- (void)requestWhenInUseAuthorization __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_8_0);

// 在Info.plist文件中添加如下配置:KEY: NSLocationAlwaysUsageDescription KEY: NSLocationWhenInUseUsageDescription

iOS9.0 之后_manager.allowsBackgroundLocationUpdates = YES;

  • 在 CLLocation.h 对像中包含着定点的相关信息数据,其属性主要包括:

    • 【coordinate】:用来存储地理位置的 latitude和 longitude,分别表示纬度和经度,都是 foat 类型。例如:float latitude = location.coordinate.latitude;

    • 【location】:是 Colocation的实例。这里使用了Cllocationdegrees,它其实是一个  double 类型,在 corelocation 框架中用来储存 Cllocationcoordinate2D实例  coordinate 的 latitude (纬度) 和 longitude (经度)。

    • 【altitude】:表示位置的海拔高度,这个值是极不准确的。

    • 【horizontalAccuracy】:表示水平准确度,是以 coordinate为圆心的半径,返回的值越小,证明准确度越好,如果是负数,则表示  corelocation 定位失败 (当前位置数据不可用)。

    • 【verticalAccuracy】:表示垂直准确度,它的返回值与 altitude相关,所以不准确(如果是负数,代表当前位置数据不可用)。

    • 【timestamp】:用于返回定位时的时间,为 Nsdate类型。

    • 【course】 : 航向 (0.0----359.9);【speed】 : 速度;【floor】 : 楼层。

    • 【distanceFromLocation】 : 计算两个坐标之间的物理直线距离 (单位:米)。

    • didUpdateLocations:(NSArray<CLLocation *> *)locations 定位时调用; didFailWithError:(NSError *)error定位失败调用。

  • 定位功能基本使用【核心类:CLLocationManager位置管理者】

// #define isIOS(Version) ([[UIDevice currentDevice].systemVersion doubleValue] >= Version)
/** 位置管理者 */
- (CLLocationManager *)manager
{
    if (_manager == nil) {
        // 1.创建位置管理者
        _manager = [[CLLocationManager alloc] init];
        // 2.使用代理告诉外界定位信息
        _manager.delegate = self;
        // 设置过滤距离
        _manager.distanceFilter = 10;
        // 设置定位精度
        _manager.desiredAccuracy = kCLLocationAccuracyBest;
        
        
        // 如果没有授权,则请求用户授权
        if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) {
            //--------------------------- 【ios8.0+定位适配】 ------------------------------//
            
            if (isIOS(8.0)) {
       
                // 请求前台定位授权,需在Info.plist中配置Key:NSLocationWhenInUseUsageDescription
                // 如果想要在后台获取用户位置, 必须勾选后台模式 location updates, 但是会出现一个蓝条不断发提醒用户.
                [_manager requestWhenInUseAuthorization];
                
                // 请求前后台定位授权,需在Info.plist中配置Key:NSLocationAlwaysUsageDescription
                // 默认情况下, 无论是在前台还是后台, 都可以获取用户位置信息, 而且不会出现蓝条.
                //[_manager requestAlwaysAuthorization];
                

                //---------------- 【ios9.0+定位适配】 -------------------//
                
                // 如果在iOS9.0,当前处前台定位授权状态下,那么即使勾选了后台模式 location updates, 也不会获取用户位置,除非设置下面属性为YES;
                if (isIOS(9.0)) {
                    _manager.allowsBackgroundLocationUpdates = YES;
                }
            }     
        }
    }
    return _manager;
}

- (void)viewDidLoad{
    [super viewDidLoad];
    if (![CLLocationManager locationServicesEnabled]) {
        NSLog(@"定位服务当前可能尚未打开,不可用");
        return;
    }
    
    [self.manager startUpdatingLocation]; // 开启定位器
}

#pragma mark ------------------
#pragma mark - <CLLocationManagerDelegate>
/**
 *【当获取到用户位置信息时,调用此方法】
 *
 * @参数: manager   位置管理者
 * @参数: locations 位置数组
 * (NSArray<CLLocation *> *): id + 泛型,数组里面的对象和这个数组的关系 is kind of
 * 在这里拿到位置信息,做一些业务逻辑操作:如获取用户所在城市(一次)。停止更新用户位置信息是调用 [manager stopUpdatingLocation];
 */
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
    NSLog(@"定位成功");
    
    // 按时间排序,要拿到最新的位置直接取最后一个
    CLLocation *location = [locations lastObject];
    CLLocationCoordinate2D coordinate = location.coordinate;
    
    NSLog(@"经度%f , 纬度%f",coordinate.longitude,coordinate.latitude);
    NSLog(@"海拔:%f,方向:%f,速度:%f",location.altitude,location.course,location.speed);

  /*【打印结果】
    用户未决定
    前台定位授权
    定位成功
   【打印结果】
    经度-122.025860 , 纬度37.330189
    海拔:0.000000,方向:91.550000,速度:7.640000
    */
}

/**
 【定位失败时调用】
 */
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
    NSLog(@"定位失败");
}


/**
 *【当前定位授权状态发生改变时调用】
 */
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
    switch (status) {
        case kCLAuthorizationStatusNotDetermined:
        {
            NSLog(@"用户未决定");
            break;
        }
        case kCLAuthorizationStatusDenied: //【否认】
        {
            //【判断当前设备是否支持定位, 定位服务是否开启】
            if([CLLocationManager locationServicesEnabled])
            {
                NSLog(@"真正被拒绝");
                
                /**
                 【被拒绝后,显示提醒给APP 授权】
                  iOS8.0- , 截图
                  iOS8.0+ , 通过调用 UIApplicationOpenSettingsURLString 方法, 来直接到达设置界面
                 */
                NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
                if ([[UIApplication sharedApplication] canOpenURL:url]) {
                    [[UIApplication sharedApplication] openURL:url];
                }
            }
            else
            {
                NSLog(@"定位服务被关闭");
            }
            break;
        }
        case kCLAuthorizationStatusRestricted://【系统预留字段】
        {
            NSLog(@"受限制");
            break;
        }
        case kCLAuthorizationStatusAuthorizedAlways:
        {
            NSLog(@"前后台定位授权");
            break;
        }
        case kCLAuthorizationStatusAuthorizedWhenInUse:
        {
            NSLog(@"前台定位授权");
            break;
        }     
        default:
            break;
    }
}
  • 【场景示例】:打印当前用户的行走方向,偏离角度以及对应的行走距离,如:”北偏东30度方向,移动了16米”

#pragma mark ------------------
#pragma mark - <CLLocationManagerDelegate>
/**
 *【当获取到用户位置信息时,调用此方法】
 */
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
    NSLog(@"定位成功");

    
    //--------------------------- 我是分割线 ------------------------------//
    //【功能: 如果水平精确度小于零, 代表虽然可以获取位置对象, 但是数据错误, 不可用 】
    if (location.horizontalAccuracy < 0) return;
    
    // 1.确定当前的航向,将当前航向值/90度会得到对应的值(0,1,2,3)
    NSInteger index = (int)(location.course / 90);
    NSArray *courseStrArray = @[@"北偏东", @"东偏南", @"南偏西", @"西偏北"];
    NSString *courseStr = courseStrArray[index];
    
    // 2.确定偏离角度
    NSInteger angle = (int)location.course % 90;
    // 判断是否为正方向,对角度取余,为0表示正
    if (angle == 0) {
        // 字符串拼接和截取
        courseStr = [@"正" stringByAppendingString:[courseStr substringToIndex:1]];
    }
    
    // 3.确定行走距离
    CGFloat distance = 0;
    
    // 判断位置是否存在
    if (_lastLoc) {
        distance = [location distanceFromLocation:_lastLoc];
    }
    // 记录位置
    _lastLoc = location;
    
    
    // 4.打印
    NSString *noticeStr;
    if (angle != 0) {
        noticeStr = [NSString stringWithFormat:@"%@ %zd 度方向, 移动了 %f米", courseStr, angle, distance];
    } else {
        noticeStr = [NSString stringWithFormat:@"%@ 方向, 移动了 %f米", courseStr, distance];
    }
    
    NSLog(@"%f  -  %@",location.course,noticeStr);
    
    self.label.text = noticeStr;
    [self.label sizeToFit];
    self.label.center = self.view.center;
}

  • 区域监听【主要类:CLCircularRegion区域】

    • 区 域 : 就是指划定的一块地域范围 (比如圆形区域,则由区域中心,和半径组成)

    • 区域监听 : 是指我们通过代码指定一个区域,然后当用户持握设备进入或者离开指定区域,我们都能监听到。

    • 监听指定区域:步骤和代码如下;

/** 位置管理者 */
// 1.导入CoreLocation框架以及对应的主头文件
- (CLLocationManager *)locationManager
{
    if(_locationManager == nil) {
        // 2.创建CLLocationManager对象并设置代理
        _locationManager = [[CLLocationManager alloc] init];
        _locationManager.delegate = self;
        
        // 3.请求前后台定位, 或前台定位授权, 并在Info.Plist文件中配置相应的Key
        if (isIOS(8.0)) {
            [_locationManager requestAlwaysAuthorization];
        }
         
    }
    return _locationManager;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor whiteColor];

    // 4.判断区域监听服务是否可用(定位服务是否关闭, 定位是否授权, 是否开启飞行模式)
    if ([CLLocationManager isMonitoringAvailableForClass:[CLCircularRegion class]])
    {
        //【判断当前设置是否支持区域监听(区域类型)】
        if (![CLLocationManager isMonitoringAvailableForClass:[CLCircularRegion class]]) return;
        
        // 创建区域中心
        CLLocationCoordinate2D center = CLLocationCoordinate2DMake(30.287574, 120.150865);
        
        // 创建区域半径
        CLLocationDistance distance = 1000.0;
        // 因为监听区域有最大值,所以要判断下是否超过监听的最大值
        if (distance > self.locationManager.maximumRegionMonitoringDistance) {
            distance = self.locationManager.maximumRegionMonitoringDistance;
        }
        // 创建一个区域
        CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:center radius:distance identifier:@"测试区域监听标识1"];
        
        //【监听一个区域(只有用户进入区域,或者离开区域动作的时候,才会通过代理告诉外界)】
        [self.locationManager startMonitoringForRegion:region];
        
        //【请求某个区域的状态(不止可以获取到指定区域的状态, 而且当状态发生变化时, 也会调用对应的代理方法, 告诉我们)】
        [self.locationManager requestStateForRegion:region];
    } else {
        NSLog(@"区域监听不可用");
    }
}


#pragma mark ------------------
#pragma mark - <CLLocationManagerDelegate>
// 5.在对应的代理方法中监听区域状态
/**
 *  进入指定区域时调用(调用一次)
 *
 *  @param manager 位置管理者
 *  @param region  区域
 */
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
    NSLog(@"进入区域 -- %@",region.identifier);
    self.noticeLabel.text = [NSString stringWithFormat:@"进入区域 -- %@",region.identifier];
}


/**
 *  离开指定区域时调用(调用一次)
 *
 *  @param manager 位置管理者
 *  @param region  区域
 */
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
    NSLog(@"离开区域 -- %@",region.identifier);
    self.noticeLabel.text = [NSString stringWithFormat:@"离开区域 -- %@",region.identifier];
}


/**
 *  当前请求指定区域状态时, 回调的代理方法
 *
 *  @param manager 位置管理者
 *  @param state   状态
 *  @param region  区域
 */
- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
{
    /**
     CLRegionStateUnknown, // 不知道
     CLRegionStateInside, // 在区域内部
     CLRegionStateOutside // 在区域外部
     */
    if (state == CLRegionStateInside) {
        self.noticeLabel.text = @"状态:在区域内部";
    } else if (state == CLRegionStateOutside){
        self.noticeLabel.text = @"状态:在区域外部";
    }
}

  • (反) 地理编码【主要类:CLGeocoder地理编码管理器】

    • 地理编码:是指根据(地址关键字),将其转换成为对应的(经纬度)等信息;

    • 反地理编码:是指根据经(纬度信息),将其转换成为对应的(省市区街道)等信息;

    • (反)地理编码:步骤和代码如下;

//【根据地址关键字, 进行地理编码】
[self.geoCoder geocodeAddressString:address completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
    CLPlacemark *placeM = [placemarks firstObject];
    
    if (error == nil) {
        NSLog(@"获取坐标:维度 %f -- 经度 %f",placeM.location.coordinate.latitude,placeM.location.coordinate.longitude);
        NSLog(@"获取地址:%@",placeM.name);
        NSLog(@"获取城市:%@",placeM.locality);
    }
}];
//【根据经纬度信息, 进行反地理编码】
[self.geoCoder reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
}];

附: CLPlacemark 地标对象属性
    location            : CLLocation 类型, 位置对象信息, 里面包含经纬度, 海拔等等
    region              : CLRegion 类型, 地标对象对应的区域
    addressDictionary   : NSDictionary 类型, 存放街道,省市等信息
    name                : NSString 类型, 地址全称
    thoroughfare        : NSString 类型, 街道名称
    locality            : NSString 类型, 城市名称
    administrativeArea  : NSString 类型, 省名称
    country             : NSString 类型, 国家名称

MapKit 地图框架


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

【MapKit核心类:MKMapView 展示地图】 《WechatPublic-Codeidea》
1.【属性】:
 
    -【用户位置跟踪】
    @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 showsPointsOfInterest;// 是否显示兴趣点
    @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;
    // 点击了大头针副展示图调用 (按钮)
    - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control __TVOS_PROHIBITED;
    // 显示地图上的大头针,注解: 当该方法不实现或者返回nil时,就会默认显示系统的大头针,类似于tableView的cellForRowAtIndexPath:
    - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation;


【MKAnnotationView:用于标注具体位置的大头针】
 
 1.【属性】
 
    @property (nonatomic, strong, nullable)     id <MKAnnotation> annotation;//数据模型
    @property (nonatomic, strong, nullable)     UIImage *image;//大头针的图像
    @property (strong, nonatomic, nullable)     UIView *leftCalloutAccessoryView;//左附属对话框
    @property (strong, nonatomic, nullable)     UIView *rightCalloutAccessoryView;//右附属对话框
    @property (nonatomic, getter=isDraggable)   BOOL draggable //是否可拖动
 
 
 2.【对象方法】
 
    // 增加大头针数据模型时会调用,类似于tableView的cellForRowAtIndexPath:
    - (nullable MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation;
    // 大头针被点击时调用
    - (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view NS_AVAILABLE(10_9, 4_0);
 

3.【MKAnnotation:是MKAnnotationView的数据源】
    @interface LNAnnotation : NSObject <MKAnnotation>;任何遵守该协议的对象都可以成为MKAnnotationView的数据源

    @property (nonatomic, readonly) CLLocationCoordinate2D coordinate; //坐标
    @property (nonatomic, readonly, copy, nullable) NSString *title;//标题
    @property (nonatomic, readonly, copy, nullable) NSString *subtitle;//副标题

    - (void)setCoordinate:(CLLocationCoordinate2D)newCoordinate ;//设置坐标
 
 
4.【补充:Callout(大头针弹框)《WechatPublic-Codeidea》】
    点击大头针(MKAnnotationView大头针),会出现一个白底的对话框,它被叫做 Callout,可以设置它的主标题和副标题。还有左右附属示图,它们可以显示图片或者按钮,也可被点击。
    annotationView.canShowCallout = YES; // 显示弹框
仿写系统的加载大头针视图的实现
#pragma mark ------------------
#pragma mark - 【仿写系统的加载大头针视图的实现】

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
    static NSString *pinID = @"pinID";
    MKPinAnnotationView *pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:pinID];
    if (pinView == nil) {
        pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:pinID];
    }
     
    pinView.annotation = annotation; // 重新赋值数据模型
    //【设置弹框】
    pinView.canShowCallout = YES;
    //【设置大头针颜色】
    pinView.pinTintColor = [UIColor blueColor];
    //【设置大头针视图下落动画】
    pinView.animatesDrop = YES;
    
    return pinView;
}
MapKit 自定义大头针
  • 自定义大头针

  • 自定义大头针视图

BaiduMap


喜欢可 赞赏支持or Sta r一波;点击左上角关注 或 微众『Codeidea』,在 Demo 更新时收到邮件通知,便捷你的阅读。


说明:针对定位和三方地图模块学习(包括系统 .h 文件),将会续更 ~ ,续更内容劳驾你(点击底部阅读原文查看)。

欢迎扫描\长按识别二维码   搜索  Codeidea 

关注微众圈     高效你的阅读

『会续更的 ~』

评论
说说你的看法