● 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