UI进阶 地图

一、地图的简介

在移动互联网时代,移动app能解决用户的很多生活琐事,比如
    导航:去任意陌生的地方
    周边:找餐馆、找酒店、找银行、找电影院
    手机软件:微信摇一摇、QQ附近的人、微博、支付宝等

在上述应用中,都用到了地图和定位功能,在iOS开发中,要想加入这两大功能,必须基于两个框架进行开发
    Map Kit :用于地图展示
    Core Location :用于地理定位

二、地图定位

CoreLocation框架的使用:

导入头文件
        #import <CoreLocation/CoreLocation.h>
CoreLocation框架使用须知
        CoreLocation框架中所有数据类型的前缀都是CL
        CoreLocation中使用CLLocationManager对象来做用户定位

CLLocationManager定位管理器类的常用操作

1、开启用户定位

1 - (void)startUpdatingLocation;

 2、停止用户定位

1 - (void) stopUpdatingLocation;

3、当调用了startUpdatingLocation方法后,就开始不断地定位用户的位置,中途会频繁地调用下面的代理方法,参数locations中的元素对象是CLLocation对象

1 - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations;

4、每隔多少米定位一次

1 @property(assign, nonatomic) CLLocationDistance distanceFilter;

5、定位精确度,越精确就越耗电

1 @property(assign, nonatomic) CLLocationAccuracy desiredAccuracy;

6、CLLocationAccuracy 是一个枚举值

最佳导航
  kCLLocationAccuracyBestForNavigation
最精准
     kCLLocationAccuracyBest;
10米
     kCLLocationAccuracyNearestTenMeters;
百米
   kCLLocationAccuracyHundredMeters;
千米
     kCLLocationAccuracyKilometer;
3千米
     kCLLocationAccuracyThreeKilometers;

 

实现定位只需要下面几步:

1.  创建管理者对象
  self.manager = [[CLLocationManager alloc] init];
2.  设置代理
  self.manager.delegate = self;
3.  开启定位
  [self.manager startUpdatingLocation];

注意:从iOS 7之后,苹果在保护用户隐私方面做了很大的加强,以下操作都必须经过用户批准授权:
①要想获得用户的位置和访问用户的通讯录、日历、相机、相册等等都需要用户来手动授权。
②当想访问用户的隐私信息时,系统会自动弹出一个对话框让用户授权 

4 、请求授权 (授权方式根据实际情况进行选择)
 [self.manager requestAlwaysAuthorization];  // 请求前台和后台定位
 [self.manager requestWhenInUseAuthorization];  // 试用期间定位

请求授权后开发者需要在Info.plist中设置NSLocationUsageDescription说明定位的目的

请求了哪几种授权就要设置它们对应的NSLocationUsageDescription

requestAlwaysAuthorization 对应的NSLocationUsageDescription是NSLocationAlwaysUsageDescription

requestWhenInUseAuthorization 对应的NSLocationUsageDescription是NSLocationWhenInUseUsageDescription

CLLocationManager有个类方法可以判断当前设备隐私设置中定位服务是否开启

1 + (BOOL)locationServicesEnabled;

 

 

CLLocation

CLLocation用来表示某个位置的地理信息,比如经纬度、海拔等等

 1 // 经纬度
 2 @property(readonly, nonatomic) CLLocationCoordinate2D coordinate;
 3 
 4 // 海拔
 5 @property(readonly, nonatomic) CLLocationDistance altitude;
 6 
 7 // 路线,航向(取值范围是0.0° ~ 359.9°,0.0°代表正北方向)
 8 @property(readonly, nonatomic) CLLocationDirection course;
 9 
10 // 行走速度(单位是m/s)
11 @property(readonly, nonatomic) CLLocationSpeed speed;
12 
13 // 此方法可以计算2个位置(CLLocation)之间的距离
14 - (CLLocationDistance)distanceFromLocation:(const CLLocation *)location

 

 

CLLocationCoordinate2D

CLLocationCoordinate2D是一个用来表示经纬度的结构体,定义如下
typedef struct {
    CLLocationDegrees latitude; // 纬度
    CLLocationDegrees longitude; // 经度
} CLLocationCoordinate2D;

一般用CLLocationCoordinate2DMake函数来创建CLLocationCoordinate2D

 

模拟位置

如果是模拟器,需要设置模拟位置(经纬度)
北京的经纬度是:北纬40°,东经116°
大连的经纬度是:北纬39°,东经121°
郑州的经纬度是:北纬34°,东经113°
上海的经纬度是:北纬31°,东经121°
广州的经纬度是:北纬23°,东经113°
西安的经纬度是:北纬34°,东经108°

 

地理编码与地理反编码

使用CLGeocoder可以完成"地理编码"和"反地理编码"
地理编码:根据给定的地名,获得具体的位置信息(比如经纬度、地址的全称等)
反地理编码:根据给定的经纬度,获得具体的位置信息

1 // 地理编码方法
2 - (void)geocodeAddressString:(NSString *)addressString completionHandler:(CLGeocodeCompletionHandler)completionHandler;
3 
4 // 反地理编码方法
5 - (void)reverseGeocodeLocation:(CLLocation *)location completionHandler:(CLGeocodeCompletionHandler)completionHandler;

 

CLGeocodeCompletionHandler

1 // 当地理编码/反地理编码完成时,就会调用CLGeocodeCompletionHandler
2 typedef void (^CLGeocodeCompletionHandler)(NSArray *placemarks, NSError *error);
3 
4 block包含2个参数
5 error:当编码出错时(比如编码不出具体的信息),2其错误信息会包含在error中
6 placemarks:里面装着CLPlacemark对象

 

CLPlacemark 

 CLPlacemark的字面意思是地标,封装详细的地址位置信息

// 地理位置
@property (nonatomic, readonly) CLLocation *location;

// 区域
@property (nonatomic, readonly) CLRegion *region;

// 详细的地址信息
@property (nonatomic, readonly) NSDictionary *addressDictionary;

// 地址名称
@property (nonatomic, readonly) NSString *name;

// 地点名称 
@property (nonatomic, readonly) NSString *locality;

 

定位的完整代码:定位、编码和反编码、计算两地之间距离

  1 #import "ViewController.h"
  2 // 引入头文件
  3 #import <CoreLocation/CoreLocation.h>
  4 
  5 @interface ViewController ()<CLLocationManagerDelegate>
  6 /// CoreLocation框架中的CLLocationManager是用来管理定位的管理器
  7 @property (nonatomic, strong) CLLocationManager *manager;
  8 /// CoreLocation框架中的CLGeocoder能进行编码和反编码
  9 @property (nonatomic, strong)CLGeocoder *geocoder;
 10 @end
 11 
 12 @implementation ViewController
 13 
 14 - (void)viewDidLoad {
 15     [super viewDidLoad];
 16     // 定位的步骤
 17     // 1、初始化定位管理器
 18     self.manager = [[CLLocationManager alloc] init];
 19     // 2、判断隐私中的定位服务是否开启并授权,如果用户允许定位才能开启相关功能
 20     /**
 21      *    NSLocationWhenInUseUsageDescription来告诉用户使用定位服务的目的,并且注意这个配置是必须的,如果不进行配置则默认情况下应用无法使用定位服务,打开应用不会给出打开定位服务的提示,除非安装后自己设置此应用的定位服务。同时,在应用程序中需要根据配置对requestAlwaysAuthorization或locationServicesEnabled方法进行请求。由于本人机器已经更新到最新的iOS8.1下面的内容主要针对iOS8,使用iOS7的朋友需要稍作调整。
 22      */
 23     if (![CLLocationManager locationServicesEnabled]) {
 24         // 手机隐私设置中定位服务没开启会执行下列代码
 25         NSLog(@"定位服务没有开启");
 26     }
 27     // 根据状态进行授权
 28     // 判断当前系统版本
 29     if ([[[UIDevice currentDevice] systemVersion] integerValue] >= 8.0) {
 30         // 判断授权状态
 31         /**
 32          *  定位服务授权状态,返回枚举类型:
 33          kCLAuthorizationStatusNotDetermined: 用户尚未做出决定是否启用定位服务
 34          kCLAuthorizationStatusRestricted: 没有获得用户授权使用定位服务,可能用户没有自己禁止访问授权
 35          kCLAuthorizationStatusDenied :用户已经明确禁止应用使用定位服务或者当前系统定位服务处于关闭状态
 36          kCLAuthorizationStatusAuthorizedAlways: 应用获得授权可以一直使用定位服务,即使应用不在使用状态
 37          kCLAuthorizationStatusAuthorizedWhenInUse: 使用此应用过程中允许访问定位服务
 38          */
 39         if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) {
 40             // 在授权请求之前需要在info.plist中设置允许定位 -- NSLocationWhenInUseUsageDescription
 41             // 请求授权
 42             [self.manager requestWhenInUseAuthorization];
 43         }
 44     }
 45     // 3、设置管理器的代理和相关属性
 46     self.manager.delegate = self;
 47     // 设置精度,误差100米
 48     self.manager.desiredAccuracy = 100;
 49     // 设置最小更新距离, 100米更新一次
 50     self.manager.distanceFilter = 100;
 51     
 52     // 4、定位管理器开启定位
 53     [self.manager startUpdatingLocation];
 54     
 55     // ***********************编码和反编码****************************
 56     // 初始化对象
 57     self.geocoder = [[CLGeocoder alloc] init];
 58     // 根据地名获取经纬度
 59     [self getCoordinateByAddress:@"莫尔道嘎"];
 60     // 根据经纬度获取地名
 61     //    [self getAddressByLatitude:23 longitude:113];
 62     // 计算两点之间的距离
 63     [self distance];
 64 }
 65 
 66 #pragma mark - 根据地名获取相关的信息
 67 - (void) getCoordinateByAddress:(NSString *)address {
 68     // 编码方法
 69     [_geocoder geocodeAddressString:address completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
 70         // 根据返回的地标数组,取出第一个位置
 71         //        NSLog(@"地标数组 : %@", placemarks);
 72         CLPlacemark *mark = placemarks.firstObject;
 73         // 根据地标获取位置
 74         CLLocation *location = mark.location;
 75         // 根据mark获取区域
 76         CLRegion *region = mark.region;
 77         // 根据mark获取详细的地址信息
 78         NSDictionary *addressDict = mark.addressDictionary;
 79         NSLog(@"位置:%@, 区域:%@, 详细的地址信息:%@", location, region, addressDict);
 80         //        NSString *name=placemark.name;//地名
 81         //        NSString *thoroughfare=placemark.thoroughfare;//街道
 82         //        NSString *subThoroughfare=placemark.subThoroughfare; //街道相关信息,例如门牌等
 83         //        NSString *locality=placemark.locality; // 城市
 84         //        NSString *subLocality=placemark.subLocality; // 城市相关信息,例如标志性建筑
 85         //        NSString *administrativeArea=placemark.administrativeArea; // 86         //        NSString *subAdministrativeArea=placemark.subAdministrativeArea; //其他行政区域信息
 87         //        NSString *postalCode=placemark.postalCode; //邮编
 88         //        NSString *ISOcountryCode=placemark.ISOcountryCode; //国家编码
 89         //        NSString *country=placemark.country; //国家
 90         //        NSString *inlandWater=placemark.inlandWater; //水源、湖泊
 91         //        NSString *ocean=placemark.ocean; // 海洋
 92         //        NSArray *areasOfInterest=placemark.areasOfInterest; //关联的或利益相关的地标
 93     }];
 94 }
 95 
 96 #pragma mark - 根据经纬度获取地名
 97 - (void)getAddressByLatitude:(CLLocationDegrees)latitude longitude:(CLLocationDegrees)longitude {
 98     // 反编码
 99     CLLocation *location = [[CLLocation alloc] initWithLatitude:latitude longitude:longitude];
100     NSLog(@"location = %@", location);
101     [_geocoder reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
102         NSDictionary *addressDict = placemarks[0].addressDictionary;
103         NSLog(@"反编码地理位置信息 %@", addressDict);
104     }];
105 }
106 
107 #pragma mark - 计算两点之间的距离
108 - (void)distance {
109     /**
110      *  北京的经纬度是:北纬40°,东经116°
111      大连的经纬度是:北纬39°,东经121°
112      */
113     // 创建北京的location
114     CLLocation *beijingLocation = [[CLLocation alloc] initWithLatitude:40 longitude:116];
115     // 创建大连的location
116     CLLocation *dalianLocation = [[CLLocation alloc] initWithLatitude:39 longitude:121];
117     // 计算两点之间的距离
118     CLLocationDistance distance = [beijingLocation distanceFromLocation:dalianLocation];
119     NSLog(@"北京到大连的距离%lf", distance);
120     
121 }
122 
123 
124 #pragma mark - CLLocationManagerDelegate代理方法
125 #pragma mark - 定位成功后开始更新位置信息,移动的位置达到最小更新距离时也会再次调用本方法
126 - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
127     // 获取最后一次的位置
128     CLLocation *location = locations.lastObject;
129     // 获取位置(经纬度)
130     CLLocationCoordinate2D coordinate = location.coordinate;
131     NSLog(@"纬度%f, 经度%f, 海拔%f, 航向%f, 行走速度%f", coordinate.latitude, coordinate.longitude, location.altitude, location.course, location.speed);
132     /*
133      注意:
134      
135      1.定位频率和定位精度并不应当越精确越好,需要视实际情况而定,因为越精确越耗性能,也就越费电。
136      
137      2.定位成功后会根据设置情况频繁调用-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations方法,这个方法返回一组地理位置对象数组,每个元素一个CLLocation代表地理位置信息(包含经度、纬度、海报、行走速度等信息),之所以返回数组是因为有些时候一个位置点可能包含多个位置。
138      
139      3.使用完定位服务后如果不需要实时监控应该立即关闭定位服务以节省资源。
140      
141      4.除了提供定位功能,CLLocationManager还可以调用startMonitoringForRegion:方法对指定区域进行监控。
142      
143      */
144     // 为了节省电量,如果不使用定位,需要把定位管理器的定位关掉
145     [self.manager stopUpdatingLocation];
146 }
147 
148 #pragma mark - 定位失败
149 - (void)locationManager:(CLLocationManager *)manager didFailWithError:(nonnull NSError *)error{
150     // 定位失败
151     NSLog(@"定位失败");
152 }
153 
154 @end

三、地图显示

MapKit框架的使用

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

跟踪显示用户的位置

设置MKMapView的userTrackingMode属性可以跟踪显示用户的当前位置    
    MKUserTrackingModeNone :不跟踪用户的位置
    MKUserTrackingModeFollow :跟踪并在地图上显示用户的当前位置
    MKUserTrackingModeFollowWithHeading :跟踪并在地图上显示用户的当前位置,地图会跟随用户的前进方向进行旋转

下图是跟踪效果
    蓝色发光圆点就是用户的当前位置
    蓝色发光圆点和红色圆点,专业术语叫做“大头针”

 

 

地图的类型

可以通过设置MKMapView的mapType设置地图类型(mapViewType是枚举类型)
MKMapTypeStandard // 普通地图(左图)
MKMapTypeSatellite // 卫星云图 (中图)
MKMapTypeHybrid // 普通地图覆盖于卫星云图之上(右图)
MKMapTypeSatelliteFlyover NS_ENUM_AVAILABLE(10_11, 9_0) // 地形和建筑物的三维模型
MKMapTypeHybridFlyover NS_ENUM_AVAILABLE(10_11, 9_0) // 显示道路和附加元素的Flyover

 

MKMapView的代理

MKMapView是专门用来显示地图的视图,可以设置一个代理对象,用来监听地图的相关行为,常见的代理方法有:

1 // 一个位置更改默认只会调用一次,不断监测用户的当前位置时每次都会调用这个方法,把用户的最新位置(userLocation参数)传进来.
2 
3 - (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation;
4 
5 // 地图的显示区域即将发生改变的时候调用
6 - (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated;
7 
8 // 地图的显示区域已经发生改变的时候调用
9 - (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated;

MKUserLocation

MKUserLocation其实是个大头针模型,包括以下属性

// 显示在大头针上的标题
@property (nonatomic, copy) NSString *title;

// 显示在大头针上的子标题
@property (nonatomic, copy) NSString *subtitle;

// 地理位置信息(大头针钉在什么地方)
@property (readonly, nonatomic) CLLocation *location;

设置地图的显示

通过MKMapView的下列方法,可以设置地图显示的位置和区域

// 设置地图的中心点位置
@property (nonatomic) CLLocationCoordinate2D centerCoordinate;

-(void)setCenterCoordinate: (CLLocationCoordinate2D)coordinate animated:(BOOL)animated;

@property (nonatomic) MKCoordinateRegion region;
- (void)setRegion:(MKCoordinateRegion)region animated:(BOOL)animated;

MKCoordinateRegion

MKCoordinateRegion是一个用来表示区域的结构体,定义如下:

1 typedef struct {
2     CLLocationCoordinate2D center; // 区域的中心点位置
3  MKCoordinateSpan span; // 区域的跨度
4 } MKCoordinateRegion;

MKCoordinateSpan的定义

1 typedef struct {
2     CLLocationDegrees latitudeDelta; // 纬度跨度
3     CLLocationDegrees longitudeDelta; // 经度跨度
4 } MKCoordinateSpan;

大头针

地图上的大头针
钉在某个具体位置,用来标识这个位置上有特定的事物(比如这个位置是北京)

大头针模型

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

#import <MapKit/MapKit.h>
@interface MyAnnonation : NSObject <MKAnnotation>
/** 坐标位置 */
@property (nonatomic, assign) CLLocationCoordinate2D coordinate;
/** 标题 */
@property (nonatomic, copy) NSString *title; 
/** 子标题 */
@property (nonatomic, copy) NSString *subtitle; 
@end

添加大头针

1 // 初始化大头针对象
2 MyAnnonation *anno = [[MyAnnonation alloc] init];
3 
4 // 设置大头针的标题和子标题以及经纬度
5 anno.title = @"BeiJing";
6 anno.subtitle = @"welcome";
7 anno.coordinate = CLLocationCoordinate2DMake(40, 116);
8 [self.mapView addAnnotation:anno];

 大头针的基本操作

MKMapView的方法

 

 1 // 添加一个大头针
 2 - (void)addAnnotation:(id <MKAnnotation>)annotation;
 3 
 4 // 添加多个大头针
 5 - (void)addAnnotations:(NSArray *)annotations;
 6 
 7 // 移除一个大头针
 8 - (void)removeAnnotation:(id <MKAnnotation>)annotation;
 9 
10 // 移除多个大头针
11 - (void)removeAnnotations:(NSArray *)annotation

 

 

 

 显示地图完整代码:显示地图、添加大头针

MyAnnotation.h 大头针类

 1 #import <Foundation/Foundation.h>
 2 #import <MapKit/MapKit.h>
 3 @interface MyAnnotation : NSObject<MKAnnotation>
 4 // 重写协议中的三个属性coordinate(标记位置)、title(标题)、subtitle(子标题)
 5 /// 标记位置
 6 @property (nonatomic) CLLocationCoordinate2D coordinate;
 7 /// 标题
 8 @property (nonatomic, copy) NSString *title;
 9 /// 子标题
10 @property (nonatomic, copy) NSString *subtitle;
11 
12 @end

ViewController.m

 1 #import "ViewController.h"
 2 // 引入地图使用的框架MapKit
 3 #import <MapKit/MapKit.h>
 4 #import <CoreLocation/CoreLocation.h>
 5 #import "MyAnnotation.h"
 6 
 7 @interface ViewController ()<MKMapViewDelegate>
 8 /// 定位管理器
 9 @property (nonatomic, strong)CLLocationManager *locationManager;
10 /// 用来显示地图的视图控件
11 @property (nonatomic, strong)MKMapView *mapView;
12 @end
13 
14 @implementation ViewController
15 
16 - (void)viewDidLoad {
17     [super viewDidLoad];
18     // 创建视图
19     [self createMapView];
20 }
21 
22 #pragma mark - 创建视图
23 - (void)createMapView {
24     // 初始化地图视图,并添加到当前视图上
25     self.mapView = [[MKMapView alloc] initWithFrame:[UIScreen mainScreen].bounds];
26     [self.view addSubview:self.mapView];
27     // 设置代理
28     self.mapView.delegate = self;
29     // 初始化定位管理器
30     self.locationManager = [[CLLocationManager alloc] init];
31     // 判断隐私中的定位服务是否开启并授权,如果用户允许定位才能开启相关功能
32     if (![CLLocationManager locationServicesEnabled]) {
33         NSLog(@"当前设备不可用");
34     }
35     
36     if ([CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorizedWhenInUse) {
37         [self.locationManager requestWhenInUseAuthorization];
38     }
39     // 设置地图的定位追踪
40     /**
41      MKUserTrackingModeNone    不跟踪用户的当前位置
42      MKUserTrackingModeFollow   跟踪并在地图上显示用户的当前位置
43      MKUserTrackingModeFollowWithHeading  跟踪并在地图上显示用户的当前位置,地图会跟随用户的前进方向进行旋转
44      */
45     self.mapView.userTrackingMode = MKUserTrackingModeFollow;
46     /**
47      MKMapTypeStandard     普通地图
48      MKMapTypeSatellite    卫星云图
49      MKMapTypeHybrid   普通地图覆盖于卫星云图之上
50      MKMapTypeSatelliteFlyover   地形和建筑物的三维模型
51      MKMapTypeHybridFlyover  显示道路和附加元素的Flyover
52      */
53     self.mapView.mapType = MKMapTypeStandard;
54     
55     // 添加大头针
56     [self addAnnotation];
57 }
58 
59 
60 #pragma mark - 添加大头针
61 - (void)addAnnotation {
62     // 创建位置
63     CLLocationCoordinate2D location1 = CLLocationCoordinate2DMake(40, 116);
64     CLLocationCoordinate2D location2 = CLLocationCoordinate2DMake(39, 121);
65     CLLocationCoordinate2D location3 = CLLocationCoordinate2DMake(31, 121);
66     // 创建大头针
67     MyAnnotation *annotation1 = [[MyAnnotation alloc] init];
68     annotation1.coordinate = location1;
69     annotation1.title = @"BeiJing";
70     annotation1.subtitle = @"welcome";
71     
72     MyAnnotation *annotation2 = [[MyAnnotation alloc] init];
73     annotation2.coordinate = location2;
74     annotation2.title = @"dalian";
75     annotation2.subtitle = @"welcome";
76     
77     MyAnnotation *annotation3 = [[MyAnnotation alloc] init];
78     annotation3.coordinate = location3;
79     annotation3.title = @"shanghai";
80     annotation3.subtitle = @"welcome";
81     // 将大头针添加到地图视图上
82     [self.mapView addAnnotations:@[annotation1, annotation2, annotation3]];
83 }
84 
85 
86 @end

四、自定义大头针

很多情况下,需要自定义大头针的显示样式,比如显示一张图片

设置MKMapView的代理
实现下面的代理方法,返回大头针控件

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

根据传进来的(id <MKAnnotation>)annotation参数创建并返回对应的大头针控件

代理方法的使用注意
1、如果返回nil,显示出来的大头针就采取系统的默认样式
2、标识用户位置的蓝色发光圆点,它也是一个大头针,当显示这个大头针时,也会调用代理方法
3、因此,需要在代理方法中分清楚(id <MKAnnotation>)annotation参数代表自定义的大头针还是蓝色发光圆点

MKAnnotationView

地图上的大头针控件是MKAnnotationView,MKAnnotationView的使用和UITableViewCell一样都是根据重用标识符从重用池中获取的,与UITableViewCell的原理一样。
MKAnnotationView的属性:

 

 1 // 大头针模型
 2 @property (nonatomic, strong) id <MKAnnotation> annotation;
 3 
 4 // 显示的图片
 5 @property (nonatomic, strong) UIImage *image;
 6 
 7 // 是否显示标注
 8 @property (nonatomic) BOOL canShowCallout;
 9 
10 // 标注的偏移量
11 @property (nonatomic) CGPoint calloutOffset;
12 
13 // 标注右边显示什么控件
14 @property (strong, nonatomic) UIView *rightCalloutAccessoryView;
15 
16 // 标注左边显示什么控件
17 @property (strong, nonatomic) UIView *leftCalloutAccessoryView;

 

 

 

MKPinAnnotationView

MKPinAnnotationView是MKAnnotationView的子类
MKPinAnnotationView比MKAnnotationView多了2个属性

 

1 // 大头针颜色
2 @property (nonatomic) MKPinAnnotationColor pinColor;
3 
4 // 大头针第一次显示时是否从天而降
5 @property (nonatomic) BOOL animatesDrop;

 

 

 

自定义大头针完整代码:设置图片,设置左视图

MyAnnotation.h   自定义大头针类

 

 1 #import <Foundation/Foundation.h>
 2 #import <MapKit/MapKit.h>
 3 @interface MyAnnotation : NSObject<MKAnnotation>
 4 // 重写协议中的三个属性coordinate(标记位置)、title(标题)、subtitle(子标题)
 5 /// 标记位置
 6 @property (nonatomic) CLLocationCoordinate2D coordinate;
 7 /// 标题
 8 @property (nonatomic, copy) NSString *title;
 9 /// 子标题
10 @property (nonatomic, copy) NSString *subtitle;
11 // 自定义大头针
12 // 大头针图片
13 @property (nonatomic, strong)UIImage *image;
14 @end

 

 

ViewController.m

  1 #import "ViewController.h"
  2 // 引入地图使用的框架MapKit
  3 #import <MapKit/MapKit.h>
  4 #import <CoreLocation/CoreLocation.h>
  5 #import "MyAnnotation.h"
  6 
  7 @interface ViewController ()<MKMapViewDelegate>
  8 /// 定位管理器
  9 @property (nonatomic, strong)CLLocationManager *locationManager;
 10 /// 用来显示地图的视图控件
 11 @property (nonatomic, strong)MKMapView *mapView;
 12 @end
 13 
 14 @implementation ViewController
 15 
 16 - (void)viewDidLoad {
 17     [super viewDidLoad];
 18     // 创建视图
 19     [self createMapView];
 20 }
 21 
 22 #pragma mark - 创建视图
 23 - (void)createMapView {
 24     // 初始化地图视图,并添加到当前视图上
 25     self.mapView = [[MKMapView alloc] initWithFrame:[UIScreen mainScreen].bounds];
 26     [self.view addSubview:self.mapView];
 27     // 设置代理
 28     self.mapView.delegate = self;
 29     // 初始化定位管理器
 30     self.locationManager = [[CLLocationManager alloc] init];
 31     // 判断隐私中的定位服务是否开启并授权,如果用户允许定位才能开启相关功能
 32     if (![CLLocationManager locationServicesEnabled]) {
 33         NSLog(@"当前设备不可用");
 34     }
 35     
 36     if ([CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorizedWhenInUse) {
 37         [self.locationManager requestWhenInUseAuthorization];
 38     }
 39     // 设置地图的定位追踪
 40     /**
 41      MKUserTrackingModeNone    不跟踪用户的当前位置
 42      MKUserTrackingModeFollow   跟踪并在地图上显示用户的当前位置
 43      MKUserTrackingModeFollowWithHeading  跟踪并在地图上显示用户的当前位置,地图会跟随用户的前进方向进行旋转
 44      */
 45     self.mapView.userTrackingMode = MKUserTrackingModeFollow;
 46     /**
 47      MKMapTypeStandard     普通地图
 48      MKMapTypeSatellite    卫星云图
 49      MKMapTypeHybrid   普通地图覆盖于卫星云图之上
 50      MKMapTypeSatelliteFlyover   地形和建筑物的三维模型
 51      MKMapTypeHybridFlyover  显示道路和附加元素的Flyover
 52      */
 53     self.mapView.mapType = MKMapTypeStandard;
 54     
 55     // 添加大头针
 56     [self addAnnotation];
 57 }
 58 
 59 
 60 #pragma mark - 添加大头针
 61 - (void)addAnnotation {
 62     // 创建位置
 63     CLLocationCoordinate2D location1 = CLLocationCoordinate2DMake(40, 116);
 64     CLLocationCoordinate2D location2 = CLLocationCoordinate2DMake(39, 121);
 65     CLLocationCoordinate2D location3 = CLLocationCoordinate2DMake(31, 121);
 66     // 创建大头针
 67     MyAnnotation *annotation1 = [[MyAnnotation alloc] init];
 68     annotation1.coordinate = location1;
 69     annotation1.title = @"BeiJing";
 70     annotation1.subtitle = @"welcome";
 71     // *******************************
 72     // 设置图片
 73     annotation1.image = [UIImage imageNamed:@"test"];
 74     
 75     
 76     MyAnnotation *annotation2 = [[MyAnnotation alloc] init];
 77     annotation2.coordinate = location2;
 78     annotation2.title = @"dalian";
 79     annotation2.subtitle = @"welcome";
 80     // *******************************
 81     // 设置图片
 82     annotation2.image = [UIImage imageNamed:@"test"];
 83     
 84     MyAnnotation *annotation3 = [[MyAnnotation alloc] init];
 85     annotation3.coordinate = location3;
 86     annotation3.title = @"shanghai";
 87     annotation3.subtitle = @"welcome";
 88     // *******************************
 89     // 设置图片
 90     annotation3.image = [UIImage imageNamed:@"test"];
 91     
 92     
 93     // 将大头针添加到地图视图上
 94     [self.mapView addAnnotations:@[annotation1, annotation2, annotation3]];
 95 }
 96 
 97 
 98 #pragma mark - ******************************************
 99 #pragma mark - 实现自定义大头针视图的代理方法
100 // 显示大头针时才会调用的方法
101 - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
102     // 判断是否是当前自定义的大头针类
103     if ([annotation isKindOfClass:[MyAnnotation class]]) {
104         // 先定义重用标识
105         static NSString *identifier = @"AnnotationOne";
106         // 从mapView的重用池中取
107         MKAnnotationView *annotationView = [self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
108         if (annotationView == nil) {
109             annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
110             // 允许用户交互
111             annotationView.canShowCallout = YES;
112             // 设置偏移量 (显示标题和子标题的文字与大头针的偏移量)
113             annotationView.calloutOffset = CGPointMake(0, 1);
114             // 设置详情的标题和子标题的左视图
115             annotationView.leftCalloutAccessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"1"]];
116         }
117         // 修改大头针视图
118         annotationView.annotation = annotation;
119         annotationView.image = ((MyAnnotation *)annotation).image;
120         return annotationView;
121     } else {
122         return nil;
123     }
124 }
125 
126 @end

运行效果:

 

 

系统自带地图功能使用起来是非常方便的,不需要导入第三方类库等
实际项目开发可根据具体情况、需求来确定是否使用系统自带地图
可以研究一下百度地图,高德地图等功能比较全面的地图

总结:

CLLocationManager 定位的基础信息
CLLocation  位置的地理信息
CLLocationCoordinate2D  存放经纬度的结构体
CLGeocoder地理位置编码与反编码的类
CLPlacemark 地标.
MKMapView 基础地图
MKUserLocation  大头针模型
MKCoordinateRegion  显示区域的结构体
MKAnnotationView 自定义大头针控件

 

posted @ 2016-05-31 23:51  fearlessyyp  阅读(908)  评论(0编辑  收藏  举报