地图篇-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
运行效果图:
使用这个属性,系统会自动给你选择一个合适的范围.