地圖的樣式能夠手動設置, 在iOS9.0以前有3種, iOS9.0以後增長了2種git
設置方式數組
self.mapView.mapType = MKMapTypeStandard;
枚舉類型 | 對應含義 |
---|---|
MKMapTypeStandard | 標準地圖 |
MKMapTypeSatellite | 衛星地圖 |
MKMapTypeHybrid | 混合模式(標準+衛星) |
MKMapTypeSatelliteFlyover | 3D立體衛星(iOS9.0) |
MKMapTypeHybridFlyover | 3D立體混合(iOS9.0) |
地圖的旋轉, 縮放, 移動等等操做行爲均可以開啓或者關閉安全
設置方式服務器
self.customMapView.zoomEnabled = YES; // 是否縮放 self.customMapView.scrollEnabled = YES; // 是否滾動 self.customMapView.rotateEnabled = YES; // 是否旋轉 self.customMapView.pitchEnabled = NO; // 是否顯示3DVIEW
地圖上的指南針, 比例尺, 建築物, POI點均可以控制是否顯示網絡
設置方式app
self.customMapView.showsCompass = YES; // 是否顯示指南針 self.customMapView.showsScale = YES; // 是否顯示比例尺 self.customMapView.showsTraffic = YES; // 是否顯示交通 self.customMapView.showsBuildings = YES; // 是否顯示建築物 self.mapView.showsPointsOfInterest = YES; // 興趣點 self.mapView.showsBuildings = YES; // 建築物
能夠設置顯示用戶當前所在位置, 以一個藍點的形式呈如今地圖上框架
設置方式測試
方案1: self.customMapView.showsUserLocation = YES; 效果: 會在地圖上顯示一個藍點, 標識用戶所在位置; 但地圖不會縮放, 並且當用戶位置移動時, 地圖不會跟隨用戶位置移動而移動 方案2: self.customMapView.userTrackingMode = MKUserTrackingModeFollowWithHeading; 效果: 會在地圖上顯示一個藍點, 標識用戶所在位置; 並且地圖縮放到合適比例,顯示用戶位置, 當用戶位置移動時, 地圖會跟隨用戶位置移動而移動; 可是有時候失效;
注意事項: 若是要顯示用戶位置, 在iOS8.0以後, 須要主動請求用戶受權優化
1. 加載地圖數據須要聯網 2. XCode版本根據測試選擇不一樣版本(iOS9.0 只能使用 XCode7.0版本) 3. iOS系統版本根據測試選擇不一樣版本(例如地圖類型, 在iOS9.0以後纔有新增)
1. 地圖加載不顯示? 檢查網絡是否通暢 2. 地圖放的太大都是格子, 禁止瀏覽 正常, 爲了安全等緣由, 不會看的太詳細 3. 地圖運行起來APP佔用內存很是大 正常, 地圖加載了不少資源 4. 用戶位置不顯示 首先, 檢查代碼, 是否有設置顯示用戶位置,是否有進行請求位置受權 其次, 查看模擬器是否有位置信息 第三, 重置模擬器, 模擬器又發神經了.
實現代理方法ui
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation { NSLog(@"%@", userLocation); }
肯定地圖中心經緯度座標
CLLocationCoordinate2D center = CLLocationCoordinate2DMake(21.123, 121.345);
設置地圖中心爲給定的經緯度座標
[mapView setCenterCoordinate:center animated:YES];
獲取合適的區域跨度
實現當地圖區域發生改變時調用的代理代理方法, 並調整地圖區域到合適比例, 並在對應的方法中, 獲取對應的跨度信息 代碼以下: - (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated { NSLog(@"%f---%f", mapView.region.span.latitudeDelta, mapView.region.span.longitudeDelta); }
建立一個區域(包含區域中心, 和區域跨度)
CLLocationCoordinate2D center = CLLocationCoordinate2DMake(21.123, 121.345); MKCoordinateSpan span = MKCoordinateSpanMake(0.1, 0.1); MKCoordinateRegion region = MKCoordinateRegionMake(center, span);
設置地圖顯示區域
[self.mapView setRegion:region animated:YES];
跨度概念解釋
MKCoordinateSpan 跨度解釋: latitudeDelta:緯度跨度,由於南北緯各90.0度,因此此值的範圍是(0.0---180.0);此值表示,整個地圖視圖寬度,顯示多大跨度; longitudeDelta:經度跨度,由於東西經各180.0度,因此此值範圍是(0.0---360.0):此值表示,整個地圖視圖高度,顯示多大跨度; 注意:地圖視圖顯示,不會更改地圖的比例,會以地圖視圖高度或寬度較小的那個爲基準,按比例調整
MKUserLocation : 被稱做「大頭針(數據)模型」; 其實叫什麼都行,本質就是一個數據模型,只不過此模型遵循了大頭針要遵循的協議(MKAnnotation) 重要屬性: location : 用戶當前所在位置信息(CLLocation對象) title : 大頭針標註要顯示的標題(NSString對象) subtitle : 大頭針標註要顯示的子標題(NSString對象)
1. 加載地圖數據須要聯網 2. XCode版本不限 3. iOS系統版本不限
1. 地圖上的藍點爲啥不顯示? 第一: 肯定代碼是否有誤(例如, 是否顯示了用戶位置) 第二: 肯定模擬器是否設置位置 第三: 看下位置在哪, 是否是不在當前地圖顯示區域 2. 地圖跨度設置以後, 最終顯示的跨度和設置數值不一致? 由於地球的不是正方形的, 隨着用戶的位置移動, 會自動修正地圖跨度, 保持地圖不變形;
按照MVC的原則 * 在地圖上操做大頭針,其實是控制大頭針數據模型 1. 添加大頭針就是添加大頭針數據模型 2. 刪除大頭針就是刪除大頭針數據模型
自定義大頭針數據模型
1) 建立繼承自NSObject的數據模型CJAnnotation, 遵循大頭針數據模型必須遵循的協議(MKAnnotation) 2) 注意將協議@property 中的readonly 去掉;
建立大頭針數據模型, 並初始化參數
CJAnnotation *annotation = [[CJAnnotation alloc] init]; annotation.coordinate = coordinate; annotation.title = @"吖了個J"; annotation.subtitle = @"大屌哈哈";
調用地圖的添加大頭針數據模型方法
[self.customMapView addAnnotation:annotation];
NSArray *annotations = self.customMapView.annotations; [self.customMapView removeAnnotations:annotations];
場景描述:
鼠標點擊在地圖哪一個位置, 就在對應的位置添加一個大頭針, 並在標註彈框中顯示對應的城市和街道;
實現步驟
1. 獲取觸摸點在地圖上對應的座標 UITouch *touch = [touches anyObject]; CGPoint touchPoint = [touch locationInView:self.customMapView]; 2. 將座標轉換成爲經緯度 CLLocationCoordinate2D center = [self.customMapView convertPoint:touchPoint toCoordinateFromView:self.customMapView]; 3. 根據經緯度建立大頭針數據模型, 並添加在地圖上 CJAnnotation *annotation = [[CJAnnotation alloc] init]; annotation.coordinate = coordinate; annotation.title = @"吖了個J"; annotation.subtitle = @"大屌哈哈"; [self.customMapView addAnnotation:annotation]; 4. 利用反地理編碼, 獲取該點對應的城市和街道名稱, 而後修改大頭針數據模型 注意: 設置彈框數據時, 對應的大頭針數據模型應有對應的佔位數據(這樣對應的UI纔會生成,後面才能從新修改數據)
1. 加載地圖數據須要聯網 2. XCode版本不限 3. iOS系統版本不限
1. 反地理編碼沒法獲取對應的數據 第一: 檢查是否有聯網 第二: 檢查代碼是否有誤 第三: 有時存在某些位置沒有反地理編碼結果, 換個點嘗試, 若是都沒有, 排除此緣由
按照MVC的原則 1. 每當添加一個大頭針數據模型時, 地圖就會調用對應的代理方法, 查找對應的大頭針視圖,顯示在地圖上; 2. 若是該方法沒有實現, 或者返回nil, 那麼就會使用系統默認的大頭針視圖
實現當添加大頭針數據模型時,地圖回調的代理方法
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation { }
實現須知
1. 大頭針系統對應的視圖是 MKPinAnnotationView,它繼承自 MKAnnotationView 2. 地圖上的大頭針視圖,和tableview上的cell同樣,都使用「循環利用」的機制
實現代碼
static NSString *pinID = @"pinID"; MKPinAnnotationView *pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:pinID]; if (!pinView) { pinView = [[MKPinAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:pinID]; } pinView.annotation = annotation; // 彈出標註 pinView.canShowCallout = YES; // 修改大頭針顏色 pinView.pinColor = MKPinAnnotationColorPurple; // 設置大頭針從天而降 pinView.animatesDrop = YES; // 設置大頭針能夠被拖拽(父類中的屬性) pinView.draggable = YES; return pinView;
實現當添加大頭針數據模型時,地圖回調的代理方法
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation { }
實現須知
1. 若是想要自定義大頭針, 必須使用 MKAnnotationView 或者 自定義的子類 2. 可是不能直接使用系統默認的大頭針, 會無效
實現代碼
// 自定義大頭針 static NSString *pinID = @"pinID"; MKAnnotationView *customPinView = [mapView dequeueReusableAnnotationViewWithIdentifier:pinID]; if (!customPinView) { customPinView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:pinID]; } // 設置大頭針圖片 customPinView.image = [UIImage imageNamed:@"category_3"]; // 設置大頭針能夠彈出標註 customPinView.canShowCallout = YES; // 設置標註左側視圖 UIImageView *leftIV = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 40, 40)]; leftIV.image = [UIImage imageNamed:@"huba.jpeg"]; customPinView.leftCalloutAccessoryView = leftIV; // 設置標註右側視圖 UIImageView *rightIV = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 40, 40)]; rightIV.image = [UIImage imageNamed:@"eason.jpg"]; customPinView.rightCalloutAccessoryView = rightIV; // 設置標註詳情視圖(iOS9.0) customPinView.detailCalloutAccessoryView = [[UISwitch alloc] init]; return customPinView;
選中一個大頭針時調用
-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view { NSLog(@"選中%@", [view.annotation title]); }
取消選中大頭針時調用
-(void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view { NSLog(@"取消選中%@", [view.annotation title]); }
1. 加載地圖數據須要聯網 2. XCode版本不限 3. iOS系統版本不限
1. 代碼運行在低版本的XCode上, 編譯失敗 第一: 語法錯誤; XCode7.0 對於OC語法優化了一些, 須要手動調整 第二: iOS9.0的SDK, 在XCode7.0以前的版本沒有對應的API
1. 能夠將須要導航的位置丟給系統的地圖APP進行導航 2. 發送網絡請求到公司服務器獲取導航數據, 而後本身手動繪製導航 3. 利用三方SDK實現導航(百度)
代碼以下:
// 根據兩個地標對象進行調用系統導航 - (void)beginNavWithBeginPlacemark:(CLPlacemark *)beginPlacemark andEndPlacemark:(CLPlacemark *)endPlacemark { // 建立起點:根據 CLPlacemark 地標對象建立 MKPlacemark 地標對象 MKPlacemark *itemP1 = [[MKPlacemark alloc] initWithPlacemark:beginPlacemark]; MKMapItem *item1 = [[MKMapItem alloc] initWithPlacemark:itemP1]; // 建立終點:根據 CLPlacemark 地標對象建立 MKPlacemark 地標對象 MKPlacemark *itemP2 = [[MKPlacemark alloc] initWithPlacemark:endPlacemark]; MKMapItem *item2 = [[MKMapItem alloc] initWithPlacemark:itemP2]; NSDictionary *launchDic = @{ // 設置導航模式參數 MKLaunchOptionsDirectionsModeKey : MKLaunchOptionsDirectionsModeDriving, // 設置地圖類型 MKLaunchOptionsMapTypeKey : @(MKMapTypeHybridFlyover), // 設置是否顯示交通 MKLaunchOptionsShowsTrafficKey : @(YES), }; // 根據 MKMapItem 數組 和 啓動參數字典 來調用系統地圖進行導航 [MKMapItem openMapsWithItems:@[item1, item2] launchOptions:launchDic]; }
注意: CLPlacemark地標對象無法直接手動建立, 只能經過(反)地理編碼獲取
3D視圖
相似於地圖街景,加強用戶體驗 CLLocationCoordinate2D center = CLLocationCoordinate2DMake(23.132931, 113.375924); MKMapCamera *camera = [MKMapCamera cameraLookingAtCenterCoordinate:center fromEyeCoordinate:CLLocationCoordinate2DMake(center.latitude, center.longitude + 0.001) eyeAltitude:1]; self.mapView.camera = camera;
地圖截圖
// 截圖附加選項 MKMapSnapshotOptions *options = [[MKMapSnapshotOptions alloc] init]; // 設置截圖區域(在地圖上的區域,做用在地圖) options.region = self.mapView.region; // options.mapRect = self.mapView.visibleMapRect; // 設置截圖後的圖片大小(做用在輸出圖像) options.size = self.mapView.frame.size; // 設置截圖後的圖片比例(默認是屏幕比例, 做用在輸出圖像) options.scale = [[UIScreen mainScreen] scale]; MKMapSnapshotter *snapshotter = [[MKMapSnapshotter alloc] initWithOptions:options]; [snapshotter startWithCompletionHandler:^(MKMapSnapshot * _Nullable snapshot, NSError * _Nullable error) { if (error) { NSLog(@"截圖錯誤:%@",error.localizedDescription); }else { // 設置屏幕上圖片顯示 self.snapshootImageView.image = snapshot.image; // 將圖片保存到指定路徑(此處是桌面路徑,須要根據我的電腦不一樣進行修改) NSData *data = UIImagePNGRepresentation(snapshot.image); [data writeToFile:@"/Users/xxxx/Desktop/snap.png" atomically:YES]; } }];
1. 加載地圖數據須要聯網 2. XCode版本不限 3. iOS系統版本不限
1. 須要注意地標對象不能手動建立, 由於裏面的屬性是readonly; 只能經過(反)地理編碼獲取
// 根據兩個地標,向蘋果服務器請求對應的行走路線信息 - (void)directionsWithBeginPlackmark:(CLPlacemark *)beginP andEndPlacemark:(CLPlacemark *)endP { // 建立請求 MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init]; // 設置開始地標 MKPlacemark *beginMP = [[MKPlacemark alloc] initWithPlacemark:beginP]; request.source = [[MKMapItem alloc] initWithPlacemark:beginMP]; // 設置結束地標 MKPlacemark *endMP = [[MKPlacemark alloc] initWithPlacemark:endP]; request.destination = [[MKMapItem alloc] initWithPlacemark:endMP]; // 根據請求,獲取實際路線信息 MKDirections *directions = [[MKDirections alloc] initWithRequest:request]; [directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse * _Nullable response, NSError * _Nullable error) { [response.routes enumerateObjectsUsingBlock:^(MKRoute * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { NSLog(@"%@--", obj.name); [obj.steps enumerateObjectsUsingBlock:^(MKRouteStep * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { NSLog(@"%@", obj.instructions); }]; }]; }]; }
/** MKDirectionsResponse對象解析 source :開始位置 destination :結束位置 routes : 路線信息 (MKRoute對象) MKRoute對象解析 name : 路的名稱 advisoryNotices : 注意警告信息 distance : 路線長度(實際物理距離,單位是m) polyline : 路線對應的在地圖上的幾何線路(由不少點組成,可繪製在地圖上) steps : 多個行走步驟組成的數組(例如「前方路口左轉」,「保持直行」等等, MKRouteStep 對象) MKRouteStep對象解析 instructions : 步驟說明(例如「前方路口左轉」,「保持直行」等等) transportType : 經過方式(駕車,步行等) polyline : 路線對應的在地圖上的幾何線路(由不少點組成,可繪製在地圖上) 注意: MKRoute是一整條長路;MKRouteStep是這條長路中的每一截; */
1. 請求路線數據須要聯網 2. XCode版本不限 3. iOS系統版本不限
1. 類太多, 記不住咋辦? 此功能不經常使用, 只須要知道有這一個功能. 若是到時用到, 直接回過頭來找代碼;
地圖添加覆蓋層(幾何路線也是一個覆蓋層), 直接添加覆蓋層數據模型
[self.mapView addOverlay:overlay];
實現地圖添加覆蓋層數據模型時, 回調的代理方法; 經過此方法, 返回對應的渲染圖層
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay { // 建立折線渲染對象 if ([overlay isKindOfClass:[MKPolyline class]]) { MKPolylineRenderer *lineRenderer = [[MKPolylineRenderer alloc] initWithOverlay:overlay]; // 設置線寬 lineRenderer.lineWidth = 6; // 設置線顏色 lineRenderer.strokeColor = [UIColor redColor]; return lineRenderer; } }
建立圓形區域覆蓋層的數據模型
MKCircle *circle = [MKCircle circleWithCenterCoordinate:self.mapView.centerCoordinate radius:1000000];
添加覆蓋層數據模型
[self.mapView addOverlay:circle];
實現代理方法
-(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay { // 建立圓形區域渲染對象 if ([overlay isKindOfClass:[MKCircle class]]) { MKCircleRenderer *circleRender = [[MKCircleRenderer alloc] initWithOverlay:overlay]; circleRender.fillColor = [UIColor cyanColor]; circleRender.alpha = 0.6; return circleRender; } return nil; }
1. 地圖加載須要聯網 2. XCode版本不限 3. iOS系統版本不限
1. 東西太多, 記不住? 只須要記得一個思想, 按照MVC的原則, 咱們操做覆蓋層, 就是操做覆蓋層數據模型; 而後地圖, 會調用其對應的代理方法, 獲取對應的覆蓋層渲染層; 類記不住不要緊, 主要記住大體思路就能夠.