IOS MapKit框架的使用(专门用于地图显示)
一、MapKit框架使用前提
- 导入框架
- 导入主头文件#import <MapKit/MapKit.h>
- MapKit框架使用须知
- MapKit框架中所有数据类型的前缀都是MK
- MapKit有一个比较重要的UI控件 :MKMapView,专门用于地图显示
二、跟踪显示用户的位置
- 设置MKMapView的userTrackingMode属性可以跟踪显示用户的当前位置
-
MKUserTrackingModeNone :不跟踪用户的位置 MKUserTrackingModeFollow :跟踪并在地图上显示用户的当前位置 MKUserTrackingModeFollowWithHeading :跟踪并在地图上显示用户的当前位 置,地图会跟随用户的前进方向进行旋转
-
下图是跟踪效果,蓝色发光圆点就是用户的当前位置。 蓝色发光原点,专业术语叫做“大头针”
三、地图的类型
- 可以通过设置MKMapView的mapViewType设置地图类型
MKMapTypeStandard:普通地图(左图) MKMapTypeSatellite:卫星云图(中图) MKMapTypeHybrid:普通地图覆盖于卫星云图之上(右图)
四、MKMapView的代理
- MKMapView可以设置一个代理对象,用来监听地图的相关行为
- 常见的代理方法有
-(void)mapView:(MKMapView*)mapViewdidUpdateUserLocation: (MKUserLocation *)userLocation; // 调用非常频繁,不断监测用户的当前位置 。每次调用,都会把用户的最新位置(userLocation参数)传进来
-
-(void)mapView:(MKMapView*)mapViewregionWillChangeAnimated: (BOOL)animated; //地图的显示区域即将发生改变的时候调用 -(void)mapView:(MKMapView*)mapViewregionDidChangeAnimated: (BOOL)animated; //地图的显示区域已经发生改变的时候调用
五、MKUserLocation
- MKUserLocation其实是个大头针模型,包括以下属性
@property(nonatomic,copy)NSString*title; //显示在大头针上的标题 @property(nonatomic,copy)NSString*subtitle; // 显示在大头针上的子标题 @property(readonly,nonatomic)CLLocation*location; // 地理位置信息(大头针钉在什么地方?)
六、设置地图的显示
通过MKMapView的下列方法,可以设置地图显示的位置和区域
- 1.设置地图的中心点位置
@property (nonatomic) CLLocationCoordinate2D centerCoordinate; - (void)setCenterCoordinate:(CLLocationCoordinate2D)coordinate animated:(BOOL)animated;
- 2.设置地图的显示区域
@property (nonatomic) MKCoordinateRegion region; - (void)setRegion:(MKCoordinateRegion)region animated: (BOOL)animated;
七、MKCoordinateRegion
- MKCoordinateRegion是一个用来表示区域的结构体,定义如下
typedef struct { CLLocationCoordinate2D center; // 区域的中心点位置 MKCoordinateSpan span; // 区域的跨度 } MKCoordinateRegion;
- MKCoordinateSpan的定义
typedef struct { CLLocationDegrees latitudeDelta; // 纬度跨度 CLLocationDegrees longitudeDelta; // 经度跨度 } MKCoordinateSpan;
八、大头针的基本操作
-
-(void)addAnnotation:(id<MKAnnotation>)annotation; //添加一个大头针 -(void)addAnnotations:(NSArray*)annotations; //添加多个大头针 -(void)removeAnnotation:(id<MKAnnotation>)annotation; // 移除一个大头针 -(void)removeAnnotations:(NSArray*)annotations; // 移除多个大头针 (id<MKAnnotation>)annotation //大头针模型对象:用来封装大头针的数据,比如大头针的位置、标题、子标题等数据
九、大头针模型
-
新建一个大头针模型类 #import <MapKit/MapKit.h> @interface MJTuangouAnnotation : NSObject <MKAnnotation> /** 坐标位置 */ @property (nonatomic, assign) CLLocationCoordinate2D coordinate; /** 标题 */ @property (nonatomic, copy) NSString *title; /** 子标题 */ @property (nonatomic, copy) NSString *subtitle; @end
十、添加大头针
-
MJTuangouAnnotation *anno = [[MJTuangouAnnotation alloc] init]; anno.title = @"XX超市"; anno.subtitle = @"地址:XX 公交是XX"; anno.coordinate = CLLocationCoordinate2DMake(40, 116); [self.mapView addAnnotation:anno];
十一、自定义大头针
- 很多情况下,需要自定义大头针的显示样式,比如显示一张图片
-
设置MKMapView的代理 ● 实现下面的代理方法,返回大头针控件 - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation; ● 根据传进来的(id <MKAnnotation>)annotation参数创建并返回对应的大头针控 件 ● 代理方法的使用注意 ● 如果返回nil,显示出来的大头针就采取系统的默认样式 ● 标识用户位置的蓝色发光圆点,它也是一个大头针,当显示这个大头针时,也会调用代 理方法 ● 因此,需要在代理方法中分清楚(id <MKAnnotation>)annotation参数代表自定 义的大头针还是蓝色发光圆点 - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation: (id<MKAnnotation>)annotation { // 判断annotation的类型 if (![annotation isKindOfClass:[MJTuangouAnnotation class]]) return nil; // 创建MKAnnotationView static NSString *ID = @"tuangou"; MKAnnotationView *annoView = [mapView dequeueReusableAnnotationViewWithIdentifier:ID]; if (annoView == nil) { annoView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:ID]; annoView.canShowCallout = YES; } // 传递模型数据 annoView.annotation = annotation; // 设置图片 MJTuangouAnnotation *tuangouAnnotation = annotation; annoView.image = [UIImage imageNamed:tuangouAnnotation.icon]; return annoView; }
十二、MKAnnotationView
-
地图上的大头针控件是MKAnnotationView
MKAnnotationView的属性 @property(nonatomic,strong)id<MKAnnotation>annotation; //大头针模型 @property(nonatomic,strong)UIImage*image; //显示的图片 @property(nonatomic)BOOLcanShowCallout; //是否显示标注 @property(nonatomic)CGPointcalloutOffset; //标注的偏移量 @property(strong,nonatomic)UIView*rightCalloutAccessoryView; //标注右边显示什么控件 @property(strong,nonatomic)UIView*leftCalloutAccessoryView; //标注左边显示什么控件
十三、MKPinAnnotationView
-
MKPinAnnotationView是MKAnnotationView的子类 MKPinAnnotationView比MKAnnotationView多了2个属性 @property(nonatomic)MKPinAnnotationColorpinColor; //大头针颜色 @property(nonatomic)BOOLanimatesDrop; //大头针第一次显示时是否从天而降
十四、实例:
- MpaKit基本使用
/** CLLocation : 封装位置信息(经纬度、海拔) CLPlacemark : 封装地标信息(位置信息CLLocation、地名name、国家country) MKUserLocation : 封装地图上大头针的位置信息(位置信息CLLocation、标题title、子标题subtitle) CLLocationDegrees : 度数(经度、纬度) CLLocationCoordinate2D : 地理坐标(经度CLLocationDegrees longitude、纬度CLLocationDegrees latitude) MKCoordinateSpan : 跨度(经度跨度CLLocationDegrees longitudeDelta、纬度跨度CLLocationDegrees latitudeDelta) MKCoordinateRegion: 区域(中心位置CLLocationCoordinate2D center、区域跨度MKCoordinateSpan span) */ #import "HMViewController.h" #import <MapKit/MapKit.h> @interface HMViewController () <MKMapViewDelegate, CLLocationManagerDelegate> @property (weak, nonatomic) IBOutlet MKMapView *mapView; @end @implementation HMViewController - (void)viewDidLoad { [super viewDidLoad]; // 1.设置地图类型 self.mapView.mapType = MKMapTypeStandard; // 2.设置跟踪模式(MKUserTrackingModeFollow == 跟踪) self.mapView.userTrackingMode = MKUserTrackingModeFollow; // 3.设置代理(监控地图的相关行为:比如显示的区域发生了改变) self.mapView.delegate = self; } #pragma mark - MKMapViewDelegate /** * 更新到用户的位置时就会调用(显示的位置、显示范围改变) * userLocation : 大头针模型数据, 对大头针位置的一个封装(这里的userLocation描述的是用来显示用户位置的蓝色大头针) */ - (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation { userLocation.title = @"天朝帝都"; userLocation.subtitle = @"帝都是个牛逼的地方"; } /** * 地图显示的区域改变了就会调用(显示的位置、显示范围改变) */ - (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated { CLLocationCoordinate2D center = mapView.region.center; MKCoordinateSpan span = mapView.region.span; NSLog(@"中心点=(%f, %f), 区域跨度=(%f, %f)", center.longitude, center.latitude, span.longitudeDelta, span.latitudeDelta); } /** * 地图显示的区域即将改变了就会调用 */ - (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated { // NSLog(@"regionWillChangeAnimated"); } @end
- MpaKit ->显示特定位置和区域
#import "HMViewController.h" #import <MapKit/MapKit.h> @interface HMViewController () <MKMapViewDelegate> @property (weak, nonatomic) IBOutlet MKMapView *mapView; - (IBAction)backToUserLocation; @end @implementation HMViewController - (void)viewDidLoad { [super viewDidLoad]; // [self.mapView setCenterCoordinate:<#(CLLocationCoordinate2D)#>]; // 设置地图显示的中心位置 // CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(39, 116); // [self.mapView setCenterCoordinate:coordinate animated:YES]; // 设置地图显示的区域 // [self.mapView setRegion:<#(MKCoordinateRegion)#>]; // CLLocationCoordinate2D center = CLLocationCoordinate2DMake(39, 116); // MKCoordinateSpan span = MKCoordinateSpanMake(0.1, 0.1); // MKCoordinateRegion region = MKCoordinateRegionMake(center, span); // [self.mapView setRegion:region animated:YES]; self.mapView.userTrackingMode = MKUserTrackingModeFollow; self.mapView.delegate = self; } #pragma mark - MKMapViewDelegate - (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation { // [mapView setCenterCoordinate:userLocation.location.coordinate animated:YES]; CLLocationCoordinate2D center = userLocation.location.coordinate; MKCoordinateSpan span = MKCoordinateSpanMake(0.2509, 0.2256); MKCoordinateRegion region = MKCoordinateRegionMake(center, span); [self.mapView setRegion:region animated:YES]; } //- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated //{ // NSLog(@"%f %f", mapView.region.span.latitudeDelta, mapView.region.span.longitudeDelta); //} - (IBAction)backToUserLocation { CLLocationCoordinate2D center = self.mapView.userLocation.location.coordinate; [self.mapView setCenterCoordinate:center animated:YES]; } @end
- MpaKit ->添加大头针
#import "HMViewController.h" #import <MapKit/MapKit.h> #import "HMAnnotation.h" @interface HMViewController () <MKMapViewDelegate> @property (weak, nonatomic) IBOutlet MKMapView *mapView; @end @implementation HMViewController - (void)viewDidLoad { [super viewDidLoad]; // HMAnnotation *anno1 = [[HMAnnotation alloc] init]; // anno1.coordinate = CLLocationCoordinate2DMake(39, 119); // anno1.title = @"帝都"; // anno1.subtitle = @"帝都帝都帝都帝都帝都"; // // 添加一个大头针模型(模型:描述大头针的信息) // [self.mapView addAnnotation:anno1]; // // HMAnnotation *anno2 = [[HMAnnotation alloc] init]; // anno2.coordinate = CLLocationCoordinate2DMake(23, 116); // anno2.title = @"广东"; // anno2.subtitle = @"广东广东广东广东广东"; // [self.mapView addAnnotation:anno2]; /** 纬度范围:N 3°51′ ~ N 53°33′ 经度范围:E 73°33′ ~ E 135°05′ */ for (int i = 0; i<100; i++) { CLLocationDegrees latitude = 23 + arc4random_uniform(20); CLLocationDegrees longitude = 73.2 + arc4random_uniform(50); HMAnnotation *anno = [[HMAnnotation alloc] init]; anno.coordinate = CLLocationCoordinate2DMake(latitude, longitude); [self.mapView addAnnotation:anno]; } } @end
- MpaKit ->自定义大头针
#import <Foundation/Foundation.h> #import <MapKit/MapKit.h> @interface HMAnnotation : NSObject <MKAnnotation> @property (nonatomic, assign) CLLocationCoordinate2D coordinate; @property (nonatomic, copy) NSString *title; @property (nonatomic, copy) NSString *subtitle; /** * 图片名 */ @property (nonatomic, copy) NSString *icon; @end
#import "HMAnnotationView.h" #import "HMAnnotation.h" @interface HMAnnotationView() @property (nonatomic, weak) UIImageView *iconView; @end @implementation HMAnnotationView + (instancetype)annotationViewWithMapView:(MKMapView *)mapView { static NSString *ID = @"anno"; HMAnnotationView *annotationView = (HMAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:ID]; if (annotationView == nil) { // 传入循环利用标识来创建大头针控件 annotationView = [[HMAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:ID]; } return annotationView; } - (id)initWithAnnotation:(id<MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier { if (self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier]) { // 显示标题和子标题 self.canShowCallout = YES; // 左边显示一个图片 UIImageView *iconView = [[UIImageView alloc] init]; iconView.bounds = CGRectMake(0, 0, 50, 50); self.leftCalloutAccessoryView = iconView; self.iconView = iconView; } return self; } - (void)setAnnotation:(HMAnnotation *)annotation { [super setAnnotation:annotation]; self.image = [UIImage imageNamed:annotation.icon]; self.iconView.image = self.image; } @end
#import "HMViewController.h" #import <MapKit/MapKit.h> #import "HMAnnotation.h" #import "HMAnnotationView.h" @interface HMViewController () <MKMapViewDelegate> @property (weak, nonatomic) IBOutlet MKMapView *mapView; - (IBAction)add; @end @implementation HMViewController - (void)viewDidLoad { [super viewDidLoad]; self.mapView.delegate = self; self.mapView.userTrackingMode = MKUserTrackingModeFollow; } - (IBAction)add { // HMAnnotation *anno1 = [[HMAnnotation alloc] init]; // anno1.coordinate = CLLocationCoordinate2DMake(39, 119); // anno1.title = @"帝都"; // anno1.subtitle = @"帝都帝都帝都帝都帝都"; // anno1.icon = @"me"; // [self.mapView addAnnotation:anno1]; // // HMAnnotation *anno2 = [[HMAnnotation alloc] init]; // anno2.coordinate = CLLocationCoordinate2DMake(23, 116); // anno2.title = @"广东"; // anno2.subtitle = @"广东广东广东广东广东"; // anno2.icon = @"other"; // [self.mapView addAnnotation:anno2]; HMAnnotation *tg1 = [[HMAnnotation alloc] init]; tg1.title = @"xxx大饭店"; tg1.subtitle = @"全场一律15折,会员20折"; tg1.icon = @"category_1"; tg1.coordinate = CLLocationCoordinate2DMake(37, 116); [self.mapView addAnnotation:tg1]; HMAnnotation *tg2 = [[HMAnnotation alloc] init]; tg2.title = @"xxx影院"; tg2.subtitle = @"最新大片:美国队长2,即将上映。。。"; tg2.icon = @"category_5"; tg2.coordinate = CLLocationCoordinate2DMake(29, 110); [self.mapView addAnnotation:tg2]; } #pragma mark - MKMapViewDelegate - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(HMAnnotation *)annotation { // 返回nil就会按照系统的默认做法 if (![annotation isKindOfClass:[HMAnnotation class]]) return nil; // 1.获得大头针控件 HMAnnotationView *annoView = [HMAnnotationView annotationViewWithMapView:mapView]; // 2.传递模型 annoView.annotation = annotation; return annoView; } //- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation //{ // // 1.先从缓存池中取出可以循环利用的大头针控件 // static NSString *ID = @"anno"; // MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:ID]; // // // 2.缓存池中没有可以循环利用的大头针控件 // if (annotationView == nil) { // // 传入循环利用标识来创建大头针控件 // annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:ID]; // // 设置头的颜色 // annotationView.pinColor = MKPinAnnotationColorPurple; // // 从天而降 // annotationView.animatesDrop = YES; // // 显示标题和子标题 // annotationView.canShowCallout = YES; //// annotationView.calloutOffset = CGPointMake(0, -10); //// annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeContactAdd]; //// annotationView.leftCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeInfoDark]; // // // 往大头针里面添加一个按钮(测试) //// [annotationView addSubview:[UIButton buttonWithType:UIButtonTypeContactAdd]]; // } // // // 3.传递模型(更新大头针数据,覆盖掉之前的旧数据) // annotationView.annotation = annotation; // // return annotationView; //} //- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(HMAnnotation *)annotation //{ // // 1.先从缓存池中取出可以循环利用的大头针控件 // static NSString *ID = @"anno"; // MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:ID]; // // // 2.缓存池中没有可以循环利用的大头针控件 // if (annotationView == nil) { // // 传入循环利用标识来创建大头针控件 // annotationView = [[MKAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:ID]; // // 显示标题和子标题 // annotationView.canShowCallout = YES; // } // // // 3.传递模型(更新大头针数据,覆盖掉之前的旧数据) // annotationView.annotation = annotation; // // // 4.设置图片 // annotationView.image = [UIImage imageNamed:annotation.icon]; // // return annotationView; //} @end
- MpaKit ->在地图上画线
#import <Foundation/Foundation.h> #import <MapKit/MapKit.h> @interface HMAnnotation : NSObject <MKAnnotation> @property (nonatomic, assign) CLLocationCoordinate2D coordinate; @property (nonatomic, copy) NSString *title; @property (nonatomic, copy) NSString *subtitle; @end
#import "HMViewController.h" #import <MapKit/MapKit.h> #import "HMAnnotation.h" @interface HMViewController () <MKMapViewDelegate> @property (weak, nonatomic) IBOutlet MKMapView *mapView; @property (nonatomic, strong) CLGeocoder *geocoder; - (IBAction)startNavigation; @property (nonatomic, strong) MKPlacemark *sourceMKPm; @property (nonatomic, strong) MKPlacemark *destinationMKPm; @end @implementation HMViewController - (CLGeocoder *)geocoder { if (!_geocoder) { self.geocoder = [[CLGeocoder alloc] init]; } return _geocoder; } - (IBAction)startNavigation { if (self.sourceMKPm == nil || self.destinationMKPm == nil) return; // 起点 MKMapItem *sourceItem = [[MKMapItem alloc] initWithPlacemark:self.sourceMKPm]; // 终点 MKMapItem *destinationItem = [[MKMapItem alloc] initWithPlacemark:self.destinationMKPm]; // 存放起点和终点 NSArray *items = @[sourceItem, destinationItem]; // 参数 NSMutableDictionary *options = [NSMutableDictionary dictionary]; // 导航模式:驾驶导航 options[MKLaunchOptionsDirectionsModeKey] = MKLaunchOptionsDirectionsModeDriving; // 是否要显示路况 options[MKLaunchOptionsShowsTrafficKey] = @YES; // 打开苹果官方的导航应用 [MKMapItem openMapsWithItems:items launchOptions:options]; } - (void)viewDidLoad { [super viewDidLoad]; self.mapView.delegate = self; NSString *sourceAddress = @"广州"; NSString *destinationAddress = @"帝都"; [self.geocoder geocodeAddressString:sourceAddress completionHandler:^(NSArray *placemarks, NSError *error) { CLPlacemark *gzPm = [placemarks firstObject]; if (gzPm == nil) return; // 添加广州大头针 HMAnnotation *gzAnno = [[HMAnnotation alloc] init]; gzAnno.coordinate = gzPm.location.coordinate; gzAnno.title = sourceAddress; gzAnno.subtitle = gzPm.name; [self.mapView addAnnotation:gzAnno]; [self.geocoder geocodeAddressString:destinationAddress completionHandler:^(NSArray *placemarks, NSError *error) { CLPlacemark *bjPm = [placemarks firstObject]; if (bjPm == nil) return; // 添加北京大头针 HMAnnotation *bjAnno = [[HMAnnotation alloc] init]; bjAnno.coordinate = bjPm.location.coordinate; bjAnno.title = destinationAddress; bjAnno.subtitle = bjPm.name; [self.mapView addAnnotation:bjAnno]; [self drawLineWithSourceCLPm:gzPm destinationCLPm:bjPm]; }]; }]; } - (void)drawLineWithSourceCLPm:(CLPlacemark *)sourceCLPm destinationCLPm:(CLPlacemark *)destinationCLPm { if (sourceCLPm == nil || destinationCLPm == nil) return; // 1.初始化方向请求 // 方向请求 MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init]; // 设置起点 MKPlacemark *sourceMKPm = [[MKPlacemark alloc] initWithPlacemark:sourceCLPm]; request.source = [[MKMapItem alloc] initWithPlacemark:sourceMKPm]; self.sourceMKPm = sourceMKPm; // 设置终点 MKPlacemark *destinationMKPm = [[MKPlacemark alloc] initWithPlacemark:destinationCLPm]; request.destination = [[MKMapItem alloc] initWithPlacemark:destinationMKPm]; self.destinationMKPm = destinationMKPm; // 2.根据请求创建方向 MKDirections *directions = [[MKDirections alloc] initWithRequest:request]; // 3.执行请求 [directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) { if (error) return; for (MKRoute *route in response.routes) { // 添加路线遮盖(传递路线的遮盖模型数据) [self.mapView addOverlay:route.polyline]; } }]; // 遮盖 overlay } #pragma mark - 代理方法 - (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay { MKPolylineRenderer *redender = [[MKPolylineRenderer alloc] initWithOverlay:overlay]; redender.lineWidth = 5; redender.strokeColor = [UIColor blueColor]; return redender; } @end