● MapKit框架使用前提
#import <MapKit/MapKit.h>
跟踪显示用户的位置
● MKUserTrackingModeNone :不跟踪用户的位置
● MKUserTrackingModeFollow :跟踪并在地图上显示用户的当前位置
● MKUserTrackingModeFollowWithHeading :跟踪并在地图上显示用户的当前位 置,地图会跟随用户的前进方向进行旋转
● 蓝色发光圆点就是用户的当前位置
● 蓝色发光原点,专业术语叫做“大头针”
地图的类型
● 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
● @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
CLLocationCoordinate2D center; // 区域的中心点位置
MKCoordinateSpan span; // 区域的跨度
} MKCoordinateRegion;
● MKCoordinateSpan的定义
typedef struct {
CLLocationDegrees latitudeDelta; // 纬度跨度
CLLocationDegrees longitudeDelta; // 经度跨度
} MKCoordinateSpan;
大头针的基本操作
● 添加一个大头针
● 添加多个大头针
● -(void)addAnnotations:(NSArray*)annotations;
● 移除一个大头针
● -(void)removeAnnotation:(id<MKAnnotation>)annotation;
● 移除多个大头针
● -(void)removeAnnotations:(NSArray*)annotations;
● (id<MKAnnotation>)annotation参数是什么东西?
● 大头针模型对象:用来封装大头针的数据,比如大头针的位置、标题、子标题等数据
大头针模型
@interface MJTuangouAnnotation : NSObject <MKAnnotation>
/** 坐标位置 */
@property (nonatomic, assign) CLLocationCoordinate2D coordinate;
/** 标题 */
@property (nonatomic, copy) NSString *title;
/** 子标题 */
@property (nonatomic, copy) NSString *subtitle;
@end
添加大头针
anno.subtitle = @"地址:XX 公交是XX";
自定义大头针
自定义大头针
● 设置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;
}
// 设置图片
MJTuangouAnnotation *tuangouAnnotation = annotation;
annoView.image = [UIImage imageNamed:tuangouAnnotation.icon];
return annoView;
}
MKAnnotationView
● @property(nonatomic,strong)id<MKAnnotation>annotation;
• 大头针模型
● @property(nonatomic,strong)UIImage*image;
• 显示的图片
● @property(nonatomic)CGPointcalloutOffset;
• 标注的偏移量
● @property(strong,nonatomic)UIView*rightCalloutAccessoryView;
• 标注右边显示什么控件
● @property(strong,nonatomic)UIView*leftCalloutAccessoryView;
• 标注左边显示什么控件
MKPinAnnotationView
● MKPinAnnotationView是MKAnnotationView的子类
● @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