地图篇-03.展示地图
这一小节是地图展示,在这一小节要接触到一个框架:MapKit
1.展示地图
展示地图特别简单,就是调用系统的地图,有两种方式,直接上代码
第一种方式:
导入头文件
#import <MapKit/MapKit.h>
然后输入以下代码:
1 // 1.代码展示地图
2 MKMapView *mapView = [[MKMapView alloc] initWithFrame:self.view.bounds];
3
4 [self.view addSubview:mapView];
运行可见:
细心的朋友能开到地图右下角有一个高德地图,这是苹果自带的框架使用的数据是高德的,但是在国外的话就不会显示这个,可以去试试改IP显示.
第二种方法:
通过storyboard来创建

自动布局前面说过了,这里就不讲了.
注意在使用storyboard拖入mapView的时候,需要导入框架和头文件


运行得到同样的效果.
2.用户位置(蓝色小圆点)
前面已经讲到了用户位置,这里不多讲,直接上代码
1 //
2 // ViewController.m
3 // 03.展示地图
4 //
5 // Created by admin on 16/5/25.
6 // Copyright © 2016年 KXZDJ. All rights reserved.
7 //
8
9 #import "ViewController.h"
10 #import <MapKit/MapKit.h>
11
12 @interface ViewController ()
13 @property (weak, nonatomic) IBOutlet MKMapView *mapView;
14 //这里没有导入CLLocation头文件的原因是MapKit包含了
15 @property (nonatomic, strong) CLLocationManager *mgr;
16
17 @end
18
19 @implementation ViewController
20
21 -(CLLocationManager *)mgr {
22 if (!_mgr) {
23 _mgr = [[CLLocationManager alloc] init];
24 //这里不需要用到代理方法,所以不设置代理
25 }
26 return _mgr;
27 }
28
29 - (void)viewDidLoad {
30 [super viewDidLoad];
31 //获取用户位置
32 self.mapView.showsUserLocation = YES;
33 //请求用户授权,然后在info.plist文件里面配置字段NSLocationAlwaysUsageDescription
34 //这里我就不判断了,直接添加always字段.
35 [self.mgr requestAlwaysAuthorization];
36
37 }
38
39 - (void)didReceiveMemoryWarning {
40 [super didReceiveMemoryWarning];
41 // Dispose of any resources that can be recreated.
42 }
43
44 @end
运行效果:
现在就能看到地图上的蓝色小圆点了,但是:
点击小圆点弹出的提示框只显示了一个current location,能不能显示当前位置呢?肯定可以的啦,这里就要用到地理编码的知识了.
因为我们能获取到用户位置,就可以通过反地理编码,把他转换成当前位置.通过mapView的代理方法,显示出来.
3.用户详细地址
代码:
1 //
2 // ViewController.m
3 // 03.展示地图
4 //
5 // Created by admin on 16/5/25.
6 // Copyright © 2016年 KXZDJ. All rights reserved.
7 //
8
9 #import "ViewController.h"
10 #import <MapKit/MapKit.h>
11
12 @interface ViewController ()<MKMapViewDelegate>
13 @property (weak, nonatomic) IBOutlet MKMapView *mapView;
14 //这里没有导入CLLocation头文件的原因是MapKit包含了
15 @property (nonatomic, strong) CLLocationManager *mgr;
16
17 @end
18
19 @implementation ViewController
20
21 -(CLLocationManager *)mgr {
22 if (!_mgr) {
23 _mgr = [[CLLocationManager alloc] init];
24 //这里不需要用到代理方法,所以不设置代理
25 }
26 return _mgr;
27 }
28
29 - (void)viewDidLoad {
30 [super viewDidLoad];
31 //获取用户位置
32 self.mapView.showsUserLocation = YES;
33 //请求用户授权,然后在info.plist文件里面配置字段NSLocationAlwaysUsageDescription
34 //这里我就不判断了,直接添加always字段.
35 [self.mgr requestAlwaysAuthorization];
36 //设置代理
37 self.mapView.delegate = self;
38 }
39
40 - (void)didReceiveMemoryWarning {
41 [super didReceiveMemoryWarning];
42 // Dispose of any resources that can be recreated.
43 }
44 /**
45 * 当用户位置更新的时候调用
46 *
47 * @param mapView 当前地图
48 * @param userLocation 用户位置
49 */
50 -(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation {
51 //反地理编码
52 CLGeocoder *reverseGeo = [[CLGeocoder alloc] init];
53 //MKUserLocation-userLocation的属性
54 /*
55 // 如果用户的位置正在更新,返回YES.
56 @property (readonly, nonatomic, getter=isUpdating) BOOL updating;
57
58 // 如果MKMapView.showsUserLocation=NO或者用户的位置尚未确定,返回nil.
59 @property (readonly, nonatomic, nullable) CLLocation *location;
60
61 // 如果不适用MKUserTrackingModeFollowWithHeading返回nil;
62 @property (readonly, nonatomic, nullable) CLHeading *heading NS_AVAILABLE(10_9, 5_0);
63
64 // 描述用户当前位置的文本.
65 @property (nonatomic, copy, nullable) NSString *title;
66
67 // 描述用户当前位置的详细信息.
68 @property (nonatomic, copy, nullable) NSString *subtitle;
69 */
70 [reverseGeo reverseGeocodeLocation:userLocation.location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
71 //判断,如果返回的地标为空,或者error存在的时候
72 if (placemarks.count == 0 || error) {
73 NSLog(@"地理编码失败");
74 return;
75 }
76
77
78
79 //根据userLocation.location进行反地理编码获得的地址只有一个(地理编码小节中有讲)
80 CLPlacemark *clp = [placemarks firstObject];
81 //设置用户当前位置的地址
82 userLocation.title = clp.name;
83 //设置用户当前位置的详细信息
84 userLocation.subtitle = @"那小子真帅...";//这里可以打印街道,门牌号等等,这里举例.
85
86
87 }];
88
89 }
90
91 @end
运行效果图:
还好没有打脸.- -!
4.地图显示范围(经纬度跨度)
上面的地图中,显示了整个亚洲,但是我们平时使用的时候肯定想他自己定位在我们所在的城市,现在我想要改变一下这个跨度,有招!
mapView有个方法:设置区域范围
self.mapView setRegion:(MKCoordinateRegion)
他需要一个MKCoordinateRegion类型的参数,看不懂?没事,command+左键点进去,会看到如下图:

一个结构体,里面两个参数,一个CLLocationCoordinate类型的,这个我们前面讲过,坐标嘛,经纬度,所以这里的center就是把用户的经纬度用来当中心点.另外一个MKCoordinateSpan类型的,不知道?再点进去:

又是一个结构体,里面也有两个参数,首先,span:范围,宽度的意思.latitudeDelta是纬度的跨度,longitudeDelta是经度的跨度.
大概了解了之后,上代码:
1 //
2 // ViewController.m
3 // 03.展示地图
4 //
5 // Created by admin on 16/5/25.
6 // Copyright © 2016年 KXZDJ. All rights reserved.
7 //
8
9 #import "ViewController.h"
10 #import <MapKit/MapKit.h>
11
12 @interface ViewController ()<MKMapViewDelegate>
13 @property (weak, nonatomic) IBOutlet MKMapView *mapView;
14 //这里没有导入CLLocation头文件的原因是MapKit包含了
15 @property (nonatomic, strong) CLLocationManager *mgr;
16
17 @end
18
19 @implementation ViewController
20
21 -(CLLocationManager *)mgr {
22 if (!_mgr) {
23 _mgr = [[CLLocationManager alloc] init];
24 //这里不需要用到代理方法,所以不设置代理
25 }
26 return _mgr;
27 }
28
29 - (void)viewDidLoad {
30 [super viewDidLoad];
31 //获取用户位置
32 self.mapView.showsUserLocation = YES;
33 //请求用户授权,然后在info.plist文件里面配置字段NSLocationAlwaysUsageDescription
34 //这里我就不判断了,直接添加always字段.
35 [self.mgr requestAlwaysAuthorization];
36 //设置代理
37 self.mapView.delegate = self;
38
39 //中心点
40 CLLocationCoordinate2D center = CLLocationCoordinate2DMake(30.67, 104.06);
41 //跨度
42 MKCoordinateSpan span = MKCoordinateSpanMake(1.0, 1.0);
43 //范围
44 MKCoordinateRegion region = MKCoordinateRegionMake(center, span);
45
46 //地图范围
47 [self.mapView setRegion:region];
48
49 }
50
51 - (void)didReceiveMemoryWarning {
52 [super didReceiveMemoryWarning];
53 // Dispose of any resources that can be recreated.
54 }
55 /**
56 * 当用户位置更新的时候调用
57 *
58 * @param mapView 当前地图
59 * @param userLocation 用户位置
60 */
61 -(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation {
62 //反地理编码
63 CLGeocoder *reverseGeo = [[CLGeocoder alloc] init];
64 //MKUserLocation-userLocation的属性
65 /*
66 // 如果用户的位置正在更新,返回YES.
67 @property (readonly, nonatomic, getter=isUpdating) BOOL updating;
68
69 // 如果MKMapView.showsUserLocation=NO或者用户的位置尚未确定,返回nil.
70 @property (readonly, nonatomic, nullable) CLLocation *location;
71
72 // 如果不适用MKUserTrackingModeFollowWithHeading返回nil;
73 @property (readonly, nonatomic, nullable) CLHeading *heading NS_AVAILABLE(10_9, 5_0);
74
75 // 描述用户当前位置的文本.
76 @property (nonatomic, copy, nullable) NSString *title;
77
78 // 描述用户当前位置的详细信息.
79 @property (nonatomic, copy, nullable) NSString *subtitle;
80 */
81 [reverseGeo reverseGeocodeLocation:userLocation.location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
82 //判断,如果返回的地标为空,或者error存在的时候
83 if (placemarks.count == 0 || error) {
84 NSLog(@"地理编码失败");
85 return;
86 }
87
88
89
90 //根据userLocation.location进行反地理编码获得的地址只有一个(地理编码小节中有讲)
91 CLPlacemark *clp = [placemarks firstObject];
92 //设置用户当前位置的地址
93 userLocation.title = clp.name;
94 //设置用户当前位置的详细信息
95 userLocation.subtitle = @"那小子真帅...";//这里可以打印街道,门牌号等等,这里举例.
96
97
98 }];
99
100 }
101
102 @end
运行效果如下:

在上面代码中第42行,我们不知道这个范围应该是多少,不用急,有两个代理方法能带我们装X带我们飞.
代码:
1 /**
2 * 地图的范围已经改变的时候调用
3 */
4 -(void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
5 //纬度的跨度
6 CLLocationDegrees latitudeDelta = mapView.region.span.latitudeDelta;
7 //经度的跨度
8 CLLocationDegrees longitudeDelta = mapView.region.span.longitudeDelta;
9
10 NSLog(@"纬度的跨度:%f,经度的跨度:%f",latitudeDelta,longitudeDelta);
11 }
12 /**
13 * 地图的范围将要改变的时候调用
14 */
15 -(void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated {
16
17 }
这两个方法中能获取到当前地图的跨度,在模拟器上按住option键然后左键上下滑动,会看到打印如下:

可以自己试一下.
但是这种方法有点麻烦,要获取坐标等一系列操作,下面介绍一种方法,利用mapView的一个属性userTrackingMode
代码:
1 //
2 // ViewController.m
3 // 03.展示地图
4 //
5 // Created by admin on 16/5/25.
6 // Copyright © 2016年 KXZDJ. All rights reserved.
7 //
8
9 #import "ViewController.h"
10 #import <MapKit/MapKit.h>
11
12 @interface ViewController ()<MKMapViewDelegate>
13 @property (weak, nonatomic) IBOutlet MKMapView *mapView;
14 //这里没有导入CLLocation头文件的原因是MapKit包含了
15 @property (nonatomic, strong) CLLocationManager *mgr;
16
17 @end
18
19 @implementation ViewController
20
21 -(CLLocationManager *)mgr {
22 if (!_mgr) {
23 _mgr = [[CLLocationManager alloc] init];
24 //这里不需要用到代理方法,所以不设置代理
25 }
26 return _mgr;
27 }
28
29 - (void)viewDidLoad {
30 [super viewDidLoad];
31 //获取用户位置
32 self.mapView.showsUserLocation = YES;
33 //请求用户授权,然后在info.plist文件里面配置字段NSLocationAlwaysUsageDescription
34 //这里我就不判断了,直接添加always字段.
35 [self.mgr requestAlwaysAuthorization];
36 //设置代理
37 self.mapView.delegate = self;
38
39
40
41
42 //跟踪用户位置(系统会自动给你设置一个比较合适的范围)
43 self.mapView.userTrackingMode = MKUserTrackingModeFollow;
44
45 //中心点
46 // CLLocationCoordinate2D center = CLLocationCoordinate2DMake(30.67, 104.06);
47 // //跨度
48 // MKCoordinateSpan span = MKCoordinateSpanMake(1.0, 1.0);
49 // //范围
50 // MKCoordinateRegion region = MKCoordinateRegionMake(center, span);
51 //
52 // //地图范围
53 // [self.mapView setRegion:region];
54
55 }
56
57 - (void)didReceiveMemoryWarning {
58 [super didReceiveMemoryWarning];
59 // Dispose of any resources that can be recreated.
60 }
61 /**
62 * 当用户位置更新的时候调用
63 *
64 * @param mapView 当前地图
65 * @param userLocation 用户位置
66 */
67 -(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation {
68 //反地理编码
69 CLGeocoder *reverseGeo = [[CLGeocoder alloc] init];
70 //MKUserLocation-userLocation的属性
71 /*
72 // 如果用户的位置正在更新,返回YES.
73 @property (readonly, nonatomic, getter=isUpdating) BOOL updating;
74
75 // 如果MKMapView.showsUserLocation=NO或者用户的位置尚未确定,返回nil.
76 @property (readonly, nonatomic, nullable) CLLocation *location;
77
78 // 如果不适用MKUserTrackingModeFollowWithHeading返回nil;
79 @property (readonly, nonatomic, nullable) CLHeading *heading NS_AVAILABLE(10_9, 5_0);
80
81 // 描述用户当前位置的文本.
82 @property (nonatomic, copy, nullable) NSString *title;
83
84 // 描述用户当前位置的详细信息.
85 @property (nonatomic, copy, nullable) NSString *subtitle;
86 */
87 [reverseGeo reverseGeocodeLocation:userLocation.location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
88 //判断,如果返回的地标为空,或者error存在的时候
89 if (placemarks.count == 0 || error) {
90 NSLog(@"地理编码失败");
91 return;
92 }
93
94
95
96 //根据userLocation.location进行反地理编码获得的地址只有一个(地理编码小节中有讲)
97 CLPlacemark *clp = [placemarks firstObject];
98 //设置用户当前位置的地址
99 userLocation.title = clp.name;
100 //设置用户当前位置的详细信息
101 userLocation.subtitle = @"那小子真帅...";//这里可以打印街道,门牌号等等,这里举例.
102
103
104 }];
105
106 }
107
108 /**
109 * 地图的范围已经改变的时候调用
110 */
111 -(void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
112 //纬度的跨度
113 CLLocationDegrees latitudeDelta = mapView.region.span.latitudeDelta;
114 //经度的跨度
115 CLLocationDegrees longitudeDelta = mapView.region.span.longitudeDelta;
116
117 NSLog(@"纬度的跨度:%f,经度的跨度:%f",latitudeDelta,longitudeDelta);
118 }
119 /**
120 * 地图的范围将要改变的时候调用
121 */
122 -(void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated {
123
124 }
125 @end
运行效果图:

使用这个属性,系统会自动给你选择一个合适的范围.
















