出自http://my.oschina.net/are1OfBlog/blog/420034
摘要
現(xiàn)在很多社交、電商、團(tuán)購(gòu)應(yīng)用都引入了地圖和定位功能,似乎地圖功能不再是地圖應(yīng)用和導(dǎo)航應(yīng)用所特有的。的確,有了地圖和定位功能確實(shí)讓我們的生活更加豐富多彩,極大的改變了我們的生活方式。例如你到了一個(gè)陌生的地方想要查找附近的酒店、超市等就可以打開軟件搜索周邊;類似的,還有很多團(tuán)購(gòu)軟件可以根據(jù)你所在的位置自動(dòng)為你推薦某些商品。總之,目前地圖和定位功能已經(jīng)大量引入到應(yīng)用開發(fā)中。今天就和大家一起看一下iOS如何進(jìn)行地圖和定位開發(fā)。
概覽
現(xiàn)在很多社交、電商、團(tuán)購(gòu)應(yīng)用都引入了地圖和定位功能,似乎地圖功能不再是地圖應(yīng)用和導(dǎo)航應(yīng)用所特有的。的確,有了地圖和定位功能確實(shí)讓我們的生活更加豐富多彩,極大的改變了我們的生活方式。例如你到了一個(gè)陌生的地方想要查找附近的酒店、超市等就可以打開軟件搜索周邊;類似的,還有很多團(tuán)購(gòu)軟件可以根據(jù)你所在的位置自動(dòng)為你推薦某些商品。總之,目前地圖和定位功能已經(jīng)大量引入到應(yīng)用開發(fā)中。今天就和大家一起看一下iOS如何進(jìn)行地圖和定位開發(fā)。
1、定位
2、地圖
定位
要實(shí)現(xiàn)地圖、導(dǎo)航功能,往往需要先熟悉定位功能,在iOS中通過Core Location框架進(jìn)行定位操作。Core Location自身可以單獨(dú)使用,和地圖開發(fā)框架MapKit完全是獨(dú)立的,但是往往地圖開發(fā)要配合定位框架使用。在Core Location中主要包含了定位、地理編碼(包括反編碼)功能。
定位功能
定位是一個(gè)很常用的功能,如一些地圖軟件打開之后如果用戶允許軟件定位的話,那么打開軟件后就會(huì)自動(dòng)鎖定到當(dāng)前位置,如果用戶手機(jī)移動(dòng)那么當(dāng)前位置也會(huì)跟隨著變化。要實(shí)現(xiàn)這個(gè)功能需要使用Core Loaction中CLLocationManager類,首先看一下這個(gè)類的一些主要方法和屬性:
類方法說明
+ (BOOL)locationServicesEnabled;
是否啟用定位服務(wù),通常如果用戶沒有啟用定位服務(wù)可以提示用戶打開定位服務(wù)
+ (CLAuthorizationStatus)authorizationStatus;
定位服務(wù)授權(quán)狀態(tài),返回枚舉類型:
kCLAuthorizationStatusNotDetermined: 用戶尚未做出決定是否啟用定位服務(wù)
kCLAuthorizationStatusRestricted: 沒有獲得用戶授權(quán)使用定位服務(wù),可能用戶沒有自己禁止訪問授權(quán)
kCLAuthorizationStatusDenied :用戶已經(jīng)明確禁止應(yīng)用使用定位服務(wù)或者當(dāng)前系統(tǒng)定位服務(wù)處于關(guān)閉狀態(tài)
kCLAuthorizationStatusAuthorizedAlways: 應(yīng)用獲得授權(quán)可以一直使用定位服務(wù),即使應(yīng)用不在使用狀態(tài)
kCLAuthorizationStatusAuthorizedWhenInUse: 使用此應(yīng)用過程中允許訪問定位服務(wù)
屬性說明
desiredAccuracy
定位精度,枚舉類型:
kCLLocationAccuracyBest:最精確定位
CLLocationAccuracy kCLLocationAccuracyNearestTenMeters:十米誤差范圍
kCLLocationAccuracyHundredMeters:百米誤差范圍
kCLLocationAccuracyKilometer:千米誤差范圍
kCLLocationAccuracyThreeKilometers:三千米誤差范圍
distanceFilter
位置信息更新最小距離,只有移動(dòng)大于這個(gè)距離才更新位置信息,默認(rèn)為kCLDistanceFilterNone:不進(jìn)行距離限制
對(duì)象方法說明
startUpdatingLocation
開始定位追蹤,開始定位后將按照用戶設(shè)置的更新頻率執(zhí)行-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations;方法反饋定位信息
stopUpdatingLocation
停止定位追蹤
startUpdatingHeading
開始導(dǎo)航方向追蹤
stopUpdatingHeading
停止導(dǎo)航方向追蹤
startMonitoringForRegion:
開始對(duì)某個(gè)區(qū)域進(jìn)行定位追蹤,開始對(duì)某個(gè)區(qū)域進(jìn)行定位后。如果用戶進(jìn)入或者走出某個(gè)區(qū)域會(huì)調(diào)用
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
和
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region代理方法反饋相關(guān)信息
stopMonitoringForRegion:
停止對(duì)某個(gè)區(qū)域進(jìn)行定位追蹤
requestWhenInUseAuthorization
請(qǐng)求獲得應(yīng)用使用時(shí)的定位服務(wù)授權(quán),注意使用此方法前在要在info.plist中配置NSLocationWhenInUseUsageDescription
requestAlwaysAuthorization
請(qǐng)求獲得應(yīng)用一直使用定位服務(wù)授權(quán),注意使用此方法前要在info.plist中配置NSLocationAlwaysUsageDescription
代理方法說明
-(void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations;
位置發(fā)生改變后執(zhí)行(第一次定位到某個(gè)位置之后也會(huì)執(zhí)行)
- (void)locationManager:(CLLocationManager *)manager
didUpdateHeading:(CLHeading *)newHeading;
導(dǎo)航方向發(fā)生變化后執(zhí)行
- (void)locationManager:(CLLocationManager *)manager
didEnterRegion:(CLRegion *)region;
進(jìn)入某個(gè)區(qū)域之后執(zhí)行
- (void)locationManager:(CLLocationManager *)manager
didExitRegion:(CLRegion *)region;
走出某個(gè)區(qū)域之后執(zhí)行
iOS 8 還提供了更加人性化的定位服務(wù)選項(xiàng)。App 的定位服務(wù)不再僅僅是關(guān)閉或打開,現(xiàn)在,定位服務(wù)的啟用提供了三個(gè)選項(xiàng),「永不」「使用應(yīng)用程序期間」和「始終」。同時(shí),考慮到能耗問題,如果一款 App 要求始終能在后臺(tái)開啟定位服務(wù),iOS 8 不僅會(huì)在首次打開 App 時(shí)主動(dòng)向你詢問,還會(huì)在日常使用中彈窗提醒你該 App 一直在后臺(tái)使用定位服務(wù),并詢問你是否繼續(xù)允許。在iOS7及以前的版本,如果在應(yīng)用程序中使用定位服務(wù)只要在程序中調(diào)用startUpdatingLocation方法應(yīng)用就會(huì)詢問用戶是否允許此應(yīng)用是否允許使用定位服務(wù),同時(shí)在提示過程中可以通過在info.plist中配置通過配置Privacy - Location Usage Description告訴用戶使用的目的,同時(shí)這個(gè)配置是可選的。
但是在iOS8中配置配置項(xiàng)發(fā)生了變化,可以通過配置NSLocationAlwaysUsageDescription或者NSLocationWhenInUseUsageDescription來告訴用戶使用定位服務(wù)的目的,并且注意這個(gè)配置是必須的,如果不進(jìn)行配置則默認(rèn)情況下應(yīng)用無法使用定位服務(wù),打開應(yīng)用不會(huì)給出打開定位服務(wù)的提示,除非安裝后自己設(shè)置此應(yīng)用的定位服務(wù)。同時(shí),在應(yīng)用程序中需要根據(jù)配置對(duì)requestAlwaysAuthorization或locationServicesEnabled方法進(jìn)行請(qǐng)求。由于本人機(jī)器已經(jīng)更新到最新的iOS8.1下面的內(nèi)容主要針對(duì)iOS8,使用iOS7的朋友需要稍作調(diào)整。
////? KCMainViewController.m//? CoreLocation////? Created by Kenshin Cui on 14-03-27.//? Copyright (c) 2014年 Kenshin Cui. All rights reserved.//#import"KCMainViewController.h"#import@interfaceKCMainViewController(){CLLocationManager*_locationManager;}@end@implementationKCMainViewController- (void)viewDidLoad {? ? [superviewDidLoad];//定位管理器_locationManager=[[CLLocationManageralloc]init];if(![CLLocationManagerlocationServicesEnabled]) {NSLog(@"定位服務(wù)當(dāng)前可能尚未打開,請(qǐng)?jiān)O(shè)置打開!");return;? ? }//如果沒有授權(quán)則請(qǐng)求用戶授權(quán)if([CLLocationManagerauthorizationStatus]==kCLAuthorizationStatusNotDetermined){? ? ? ? [_locationManager requestWhenInUseAuthorization];? ? }elseif([CLLocationManagerauthorizationStatus]==kCLAuthorizationStatusAuthorizedWhenInUse){//設(shè)置代理_locationManager.delegate=self;//設(shè)置定位精度_locationManager.desiredAccuracy=kCLLocationAccuracyBest;//定位頻率,每隔多少米定位一次CLLocationDistancedistance=10.0;//十米定位一次_locationManager.distanceFilter=distance;//啟動(dòng)跟蹤定位[_locationManager startUpdatingLocation];? ? }}#pragma mark - CoreLocation 代理#pragma mark 跟蹤定位代理方法,每次位置發(fā)生變化即會(huì)執(zhí)行(只要定位到相應(yīng)位置)//可以通過模擬器設(shè)置一個(gè)虛擬位置,否則在模擬器中無法調(diào)用此方法-(void)locationManager:(CLLocationManager*)manager didUpdateLocations:(NSArray*)locations{CLLocation*location=[locations firstObject];//取出第一個(gè)位置CLLocationCoordinate2Dcoordinate=location.coordinate;//位置坐標(biāo)NSLog(@"經(jīng)度:%f,緯度:%f,海拔:%f,航向:%f,行走速度:%f",coordinate.longitude,coordinate.latitude,location.altitude,location.course,location.speed);//如果不需要實(shí)時(shí)定位,使用完即使關(guān)閉定位服務(wù)[_locationManager stopUpdatingLocation];}@end
注意:
1、定位頻率和定位精度并不應(yīng)當(dāng)越精確越好,需要視實(shí)際情況而定,因?yàn)樵骄_越耗性能,也就越費(fèi)電。
2、定位成功后會(huì)根據(jù)設(shè)置情況頻繁調(diào)用-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations方法,這個(gè)方法返回一組地理位置對(duì)象數(shù)組,每個(gè)元素一個(gè)CLLocation代表地理位置信息(包含經(jīng)度、緯度、海報(bào)、行走速度等信息),之所以返回?cái)?shù)組是因?yàn)橛行r(shí)候一個(gè)位置點(diǎn)可能包含多個(gè)位置。
3、使用完定位服務(wù)后如果不需要實(shí)時(shí)監(jiān)控應(yīng)該立即關(guān)閉定位服務(wù)以節(jié)省資源。
4、除了提供定位功能,CLLocationManager還可以調(diào)用startMonitoringForRegion:方法對(duì)指定區(qū)域進(jìn)行監(jiān)控。
地理編碼
除了提供位置跟蹤功能之外,在定位服務(wù)中還包含CLGeocoder類用于處理地理編碼和逆地理編碼(又叫反地理編碼)功能。
地理編碼:根據(jù)給定的位置(通常是地名)確定地理坐標(biāo)(經(jīng)、緯度)。
逆地理編碼:可以根據(jù)地理坐標(biāo)(經(jīng)、緯度)確定位置信息(街道、門牌等)。
CLGeocoder最主要的兩個(gè)方法就是- (void)geocodeAddressString:(NSString *)addressString completionHandler:(CLGeocodeCompletionHandler)completionHandler;和- (void)reverseGeocodeLocation:(CLLocation *)location completionHandler:(CLGeocodeCompletionHandler)completionHandler;,分別用于地理編碼和逆地理編碼。下面簡(jiǎn)單演示一下:
////? KCMainViewController.m//? CoreLocation////? Created by Kenshin Cui on 14-03-27.//? Copyright (c) 2014年 Kenshin Cui. All rights reserved.//#import"KCMainViewController.h"#import@interfaceKCMainViewController(){CLGeocoder*_geocoder;}@end@implementationKCMainViewController- (void)viewDidLoad {? ? [superviewDidLoad];? ? ? ? _geocoder=[[CLGeocoderalloc]init];? ? [selfgetCoordinateByAddress:@"北京"];? ? [selfgetAddressByLatitude:39.54longitude:116.28];}#pragma mark 根據(jù)地名確定地理坐標(biāo)-(void)getCoordinateByAddress:(NSString*)address{//地理編碼[_geocoder geocodeAddressString:address completionHandler:^(NSArray*placemarks,NSError*error) {//取得第一個(gè)地標(biāo),地標(biāo)中存儲(chǔ)了詳細(xì)的地址信息,注意:一個(gè)地名可能搜索出多個(gè)地址CLPlacemark*placemark=[placemarks firstObject];CLLocation*location=placemark.location;//位置CLRegion*region=placemark.region;//區(qū)域NSDictionary*addressDic= placemark.addressDictionary;//詳細(xì)地址信息字典,包含以下部分信息//? ? ? ? NSString *name=placemark.name;//地名//? ? ? ? NSString *thoroughfare=placemark.thoroughfare;//街道//? ? ? ? NSString *subThoroughfare=placemark.subThoroughfare; //街道相關(guān)信息,例如門牌等//? ? ? ? NSString *locality=placemark.locality; // 城市//? ? ? ? NSString *subLocality=placemark.subLocality; // 城市相關(guān)信息,例如標(biāo)志性建筑//? ? ? ? NSString *administrativeArea=placemark.administrativeArea; // 州//? ? ? ? NSString *subAdministrativeArea=placemark.subAdministrativeArea; //其他行政區(qū)域信息//? ? ? ? NSString *postalCode=placemark.postalCode; //郵編//? ? ? ? NSString *ISOcountryCode=placemark.ISOcountryCode; //國(guó)家編碼//? ? ? ? NSString *country=placemark.country; //國(guó)家//? ? ? ? NSString *inlandWater=placemark.inlandWater; //水源、湖泊//? ? ? ? NSString *ocean=placemark.ocean; // 海洋//? ? ? ? NSArray *areasOfInterest=placemark.areasOfInterest; //關(guān)聯(lián)的或利益相關(guān)的地標(biāo)NSLog(@"位置:%@,區(qū)域:%@,詳細(xì)信息:%@",location,region,addressDic);? ? }];}#pragma mark 根據(jù)坐標(biāo)取得地名-(void)getAddressByLatitude:(CLLocationDegrees)latitude longitude:(CLLocationDegrees)longitude{//反地理編碼CLLocation*location=[[CLLocationalloc]initWithLatitude:latitude longitude:longitude];? ? [_geocoder reverseGeocodeLocation:location completionHandler:^(NSArray*placemarks,NSError*error) {CLPlacemark*placemark=[placemarks firstObject];NSLog(@"詳細(xì)信息:%@",placemark.addressDictionary);? ? }];}@end
地圖
iOS從6.0開始地圖數(shù)據(jù)不再由谷歌驅(qū)動(dòng),而是改用自家地圖,當(dāng)然在國(guó)內(nèi)它的數(shù)據(jù)是由高德地圖提供的。這樣一來,如果在iOS6.0之前進(jìn)行地圖開發(fā)的話使用方法會(huì)有所不同,基于目前的情況其實(shí)使用iOS6.0之前版本的系統(tǒng)基本已經(jīng)寥寥無幾了,所有在接下來的內(nèi)容中不會(huì)再針對(duì)iOS5及之前版本的地圖開發(fā)進(jìn)行介紹。
在iOS中進(jìn)行地圖開發(fā)主要有兩種方式,一種是直接利用MapKit框架進(jìn)行地圖開發(fā),利用這種方式可以對(duì)地圖進(jìn)行精準(zhǔn)的控制;另一種方式是直接調(diào)用蘋果官方自帶的地圖應(yīng)用,主要用于一些簡(jiǎn)單的地圖應(yīng)用(例如:進(jìn)行導(dǎo)航覆蓋物填充等),無法進(jìn)行精確的控制。當(dāng)然,本節(jié)重點(diǎn)內(nèi)容還是前者,后面的內(nèi)容也會(huì)稍加提示。
用MapKit之前需要簡(jiǎn)單了解一下MapKit中地圖展示控件MKMapView的的一些常用屬性和方法,具體如下表:
屬性說明
userTrackingMode
跟蹤類型,是一個(gè)枚舉:
MKUserTrackingModeNone :不進(jìn)行用戶位置跟蹤;
MKUserTrackingModeFollow :跟蹤用戶位置;
MKUserTrackingModeFollowWithHeading :跟蹤用戶位置并且跟蹤用戶前進(jìn)方向;
mapType
地圖類型,是一個(gè)枚舉:
MKMapTypeStandard :標(biāo)準(zhǔn)地圖,一般情況下使用此地圖即可滿足;
MKMapTypeSatellite :衛(wèi)星地圖;
MKMapTypeHybrid :混合地圖,加載最慢比較消耗資源;
userLocation
用戶位置,只讀屬性
annotations
當(dāng)前地圖中的所有大頭針,只讀屬性
對(duì)象方法說明
- (void)addAnnotation:(id )annotation;
添加大頭針,對(duì)應(yīng)的有添加大頭針數(shù)組
- (void)removeAnnotation:(id )annotation;
刪除大頭針,對(duì)應(yīng)的有刪除大頭針數(shù)組
- (void)setRegion:(MKCoordinateRegion)region animated:(BOOL)animated;
設(shè)置地圖顯示區(qū)域,用于控制當(dāng)前屏幕顯示地圖范圍
- (void)setCenterCoordinate:(CLLocationCoordinate2D)coordinate animated:(BOOL)animated;
設(shè)置地圖中心點(diǎn)位置
- (CGPoint)convertCoordinate:(CLLocationCoordinate2D)coordinate toPointToView:(UIView *)view;
將地理坐標(biāo)(經(jīng)緯度)轉(zhuǎn)化為數(shù)學(xué)坐標(biāo)(UIKit坐標(biāo))
- (CLLocationCoordinate2D)convertPoint:(CGPoint)point toCoordinateFromView:(UIView *)view;
將數(shù)學(xué)坐標(biāo)轉(zhuǎn)換為地理坐標(biāo)
- (MKAnnotationView *)dequeueReusableAnnotationViewWithIdentifier:(NSString *)identifier;
從緩存池中取出大頭針,類似于UITableView中取出UITableViewCell,為了進(jìn)行性能優(yōu)化而設(shè)計(jì)
- (void)selectAnnotation:(id )annotation animated:(BOOL)animated;
選中指定的大頭針
- (void)deselectAnnotation:(id )annotation animated:(BOOL)animated;
取消選中指定的大頭針
代理方法說明
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation;
用戶位置發(fā)生改變時(shí)觸發(fā)(第一次定位到用戶位置也會(huì)觸發(fā)該方法)
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation;
顯示區(qū)域發(fā)生改變后觸發(fā)
- (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView;
地圖加載完成后觸發(fā)
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id )annotation;
顯示大頭針時(shí)觸發(fā),返回大頭針視圖,通常自定義大頭針可以通過此方法進(jìn)行
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
點(diǎn)擊選中某個(gè)大頭針時(shí)觸發(fā)
- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view
取消選中大頭針時(shí)觸發(fā)
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id )overlay
渲染地圖覆蓋物時(shí)觸發(fā)
用戶位置跟蹤
在很多帶有地圖的應(yīng)用中默認(rèn)打開地圖都會(huì)顯示用戶當(dāng)前位置,同時(shí)將當(dāng)前位置標(biāo)記出來放到屏幕中點(diǎn)方便用戶對(duì)周圍情況進(jìn)行查看。如果在iOS6或者iOS7中實(shí)現(xiàn)這個(gè)功能只需要添加地圖控件、設(shè)置用戶跟蹤模式、在-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation代理方法中設(shè)置地圖中心區(qū)域及顯示范圍。但是在iOS8中用法稍有不同:
1.由于在地圖中進(jìn)行用戶位置跟蹤需要使用定位功能,而定位功能在iOS8中設(shè)計(jì)發(fā)生了變化,因此必須按照前面定位章節(jié)中提到的內(nèi)容進(jìn)行配置和請(qǐng)求。
2.iOS8中不需要進(jìn)行中心點(diǎn)的指定,默認(rèn)會(huì)將當(dāng)前位置設(shè)置中心點(diǎn)并自動(dòng)設(shè)置顯示區(qū)域范圍。
了解以上兩點(diǎn),要進(jìn)行用戶位置跟蹤其實(shí)就相當(dāng)簡(jiǎn)單了,值得一提的是-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation這個(gè)代理方法。這個(gè)方法只有在定位(利用前面章節(jié)中的定位內(nèi)容)到當(dāng)前位置之后就會(huì)調(diào)用,以后每當(dāng)用戶位置發(fā)生改變就會(huì)觸發(fā),調(diào)用頻率相當(dāng)頻繁。
大頭針
在iOS開發(fā)中經(jīng)常會(huì)標(biāo)記某個(gè)位置,需要使用地圖標(biāo)注,也就是大家俗稱的“大頭針”。只要一個(gè)NSObject類實(shí)現(xiàn)MKAnnotation協(xié)議就可以作為一個(gè)大頭針,通常會(huì)重寫協(xié)議中coordinate(標(biāo)記位置)、title(標(biāo)題)、subtitle(子標(biāo)題)三個(gè)屬性,然后在程序中創(chuàng)建大頭針對(duì)象并調(diào)用addAnnotation:方法添加大頭針即可(之所以iOS沒有定義一個(gè)基類實(shí)現(xiàn)這個(gè)協(xié)議供開發(fā)者使用,多數(shù)原因應(yīng)該是MKAnnotation是一個(gè)模型對(duì)象,對(duì)于多數(shù)應(yīng)用模型會(huì)稍有不同,例如后面的內(nèi)容中會(huì)給大頭針模型對(duì)象添加其他屬性)。
KCAnnotation.h
////? KCAnnotation.h//? MapKit////? Created by Kenshin Cui on 14/3/27.//? Copyright (c) 2014年 Kenshin Cui. All rights reserved.//#import#import@interfaceKCAnnotation:NSObject@property(nonatomic)CLLocationCoordinate2Dcoordinate;@property(nonatomic,copy)NSString*title;@property(nonatomic,copy)NSString*subtitle;@end
KCMainViewController.m
////? KCMainViewController.m//? MapKit Annotation////? Created by Kenshin Cui on 14/3/27.//? Copyright (c) 2014年 Kenshin Cui. All rights reserved.//? 37.785834? -122.406417//? 39.92 116.39#import"KCMainViewController.h"#import#import#import"KCAnnotation.h"@interfaceKCMainViewController(){CLLocationManager*_locationManager;MKMapView*_mapView;}@end@implementationKCMainViewController- (void)viewDidLoad {? ? [superviewDidLoad];? ? ? ? [selfinitGUI];}#pragma mark 添加地圖控件-(void)initGUI{CGRectrect=[UIScreenmainScreen].bounds;? ? _mapView=[[MKMapViewalloc]initWithFrame:rect];? ? [self.view addSubview:_mapView];//設(shè)置代理_mapView.delegate=self;//請(qǐng)求定位服務(wù)_locationManager=[[CLLocationManageralloc]init];if(![CLLocationManagerlocationServicesEnabled]||[CLLocationManagerauthorizationStatus]!=kCLAuthorizationStatusAuthorizedWhenInUse){? ? ? ? [_locationManager requestWhenInUseAuthorization];? ? }//用戶位置追蹤(用戶位置追蹤用于標(biāo)記用戶當(dāng)前位置,此時(shí)會(huì)調(diào)用定位服務(wù))_mapView.userTrackingMode=MKUserTrackingModeFollow;//設(shè)置地圖類型_mapView.mapType=MKMapTypeStandard;//添加大頭針[selfaddAnnotation];}#pragma mark 添加大頭針-(void)addAnnotation{CLLocationCoordinate2Dlocation1=CLLocationCoordinate2DMake(39.95,116.35);? ? KCAnnotation *annotation1=[[KCAnnotation alloc]init];? ? annotation1.title=@"CMJ Studio";? ? annotation1.subtitle=@"Kenshin Cui's Studios";? ? annotation1.coordinate=location1;? ? [_mapView addAnnotation:annotation1];CLLocationCoordinate2Dlocation2=CLLocationCoordinate2DMake(39.87,116.35);? ? KCAnnotation *annotation2=[[KCAnnotation alloc]init];? ? annotation2.title=@"Kenshin&Kaoru";? ? annotation2.subtitle=@"Kenshin Cui's Home";? ? annotation2.coordinate=location2;? ? [_mapView addAnnotation:annotation2];}#pragma mark - 地圖控件代理方法#pragma mark 更新用戶位置,只要用戶改變則調(diào)用此方法(包括第一次定位到用戶位置)-(void)mapView:(MKMapView*)mapView didUpdateUserLocation:(MKUserLocation*)userLocation{NSLog(@"%@",userLocation);//設(shè)置地圖顯示范圍(如果不進(jìn)行區(qū)域設(shè)置會(huì)自動(dòng)顯示區(qū)域范圍并指定當(dāng)前用戶位置為地圖中心點(diǎn))//? ? MKCoordinateSpan span=MKCoordinateSpanMake(0.01, 0.01);//? ? MKCoordinateRegion region=MKCoordinateRegionMake(userLocation.location.coordinate, span);//? ? [_mapView setRegion:region animated:true];}@end
運(yùn)行效果:
設(shè)置大頭針視圖
在一些應(yīng)用中系統(tǒng)默認(rèn)的大頭針樣式可能無法滿足實(shí)際的需求,此時(shí)就需要修改大頭針視圖默認(rèn)樣式。根據(jù)前面MapKit的代理方法不難發(fā)現(xiàn)- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id )annotation;方法可以返回一個(gè)大頭針視圖,只要實(shí)現(xiàn)這個(gè)方法并在這個(gè)方法中定義一個(gè)大頭針視圖MKAnnotationView對(duì)象并設(shè)置相關(guān)屬性就可以改變默認(rèn)大頭針的樣式。MKAnnotationView常用屬性:
屬性說明
annotation
大頭針模型信息,包括標(biāo)題、子標(biāo)題、地理位置。
image
大頭針圖片
canShowCallout
點(diǎn)擊大頭針是否顯示標(biāo)題、子標(biāo)題內(nèi)容等,注意如果在
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id )annotation;
方法中重新定義大頭針默認(rèn)情況是無法交互的需要設(shè)置為true。
calloutOffset
點(diǎn)擊大頭針時(shí)彈出詳情信息視圖的偏移量
selected
是否被選中狀態(tài)
leftCalloutAccessoryView
彈出詳情左側(cè)視圖
rightCalloutAccessoryView
彈出詳情右側(cè)視圖
需要注意:
a.這個(gè)代理方法的調(diào)用時(shí)機(jī):每當(dāng)有大頭針顯示到系統(tǒng)可視界面中時(shí)就會(huì)調(diào)用此方法返回一個(gè)大頭針視圖放到界面中,同時(shí)當(dāng)前系統(tǒng)位置標(biāo)注(也就是地圖中藍(lán)色的位置點(diǎn))也是一個(gè)大頭針,也會(huì)調(diào)用此方法,因此處理大頭針視圖時(shí)需要區(qū)別對(duì)待。
b.類似于UITableView的代理方法,此方法調(diào)用頻繁,開發(fā)過程中需要重復(fù)利用MapKit的緩存池將大頭針視圖緩存起來重復(fù)利用。
c.自定義大頭針默認(rèn)情況下不允許交互,如果交互需要設(shè)置canShowCallout=true
d.如果代理方法返回nil則會(huì)使用默認(rèn)大頭針視圖,需要根據(jù)情況設(shè)置。
下面以一個(gè)示例進(jìn)行大頭針視圖設(shè)置,這里設(shè)置了大頭針的圖片、彈出視圖、偏移量等信息。
KCAnnotation.h
////? KCAnnotation.h//? MapKit////? Created by Kenshin Cui on 14/3/27.//? Copyright (c) 2014年 Kenshin Cui. All rights reserved.//#import#import@interfaceKCAnnotation:NSObject@property(nonatomic)CLLocationCoordinate2Dcoordinate;@property(nonatomic,copy)NSString*title;@property(nonatomic,copy)NSString*subtitle;#pragma mark 自定義一個(gè)圖片屬性在創(chuàng)建大頭針視圖時(shí)使用@property(nonatomic,strong)UIImage*image;@end
KCMainViewController.m
////? KCMainViewController.m//? MapKit Annotation////? Created by Kenshin Cui on 14/3/27.//? Copyright (c) 2014年 Kenshin Cui. All rights reserved.//? 37.785834? -122.406417//? 39.92 116.39#import"KCMainViewController.h"#import#import#import"KCAnnotation.h"@interfaceKCMainViewController(){CLLocationManager*_locationManager;MKMapView*_mapView;}@end@implementationKCMainViewController- (void)viewDidLoad {? ? [superviewDidLoad];? ? ? ? [selfinitGUI];}#pragma mark 添加地圖控件-(void)initGUI{CGRectrect=[UIScreenmainScreen].bounds;? ? _mapView=[[MKMapViewalloc]initWithFrame:rect];? ? [self.view addSubview:_mapView];//設(shè)置代理_mapView.delegate=self;//請(qǐng)求定位服務(wù)_locationManager=[[CLLocationManageralloc]init];if(![CLLocationManagerlocationServicesEnabled]||[CLLocationManagerauthorizationStatus]!=kCLAuthorizationStatusAuthorizedWhenInUse){? ? ? ? [_locationManager requestWhenInUseAuthorization];? ? }//用戶位置追蹤(用戶位置追蹤用于標(biāo)記用戶當(dāng)前位置,此時(shí)會(huì)調(diào)用定位服務(wù))_mapView.userTrackingMode=MKUserTrackingModeFollow;//設(shè)置地圖類型_mapView.mapType=MKMapTypeStandard;//添加大頭針[selfaddAnnotation];}#pragma mark 添加大頭針-(void)addAnnotation{CLLocationCoordinate2Dlocation1=CLLocationCoordinate2DMake(39.95,116.35);? ? KCAnnotation *annotation1=[[KCAnnotation alloc]init];? ? annotation1.title=@"CMJ Studio";? ? annotation1.subtitle=@"Kenshin Cui's Studios";? ? annotation1.coordinate=location1;? ? annotation1.image=[UIImageimageNamed:@"icon_pin_floating.png"];? ? [_mapView addAnnotation:annotation1];CLLocationCoordinate2Dlocation2=CLLocationCoordinate2DMake(39.87,116.35);? ? KCAnnotation *annotation2=[[KCAnnotation alloc]init];? ? annotation2.title=@"Kenshin&Kaoru";? ? annotation2.subtitle=@"Kenshin Cui's Home";? ? annotation2.coordinate=location2;? ? annotation2.image=[UIImageimageNamed:@"icon_paopao_waterdrop_streetscape.png"];? ? [_mapView addAnnotation:annotation2];}#pragma mark - 地圖控件代理方法#pragma mark 顯示大頭針時(shí)調(diào)用,注意方法中的annotation參數(shù)是即將顯示的大頭針對(duì)象-(MKAnnotationView*)mapView:(MKMapView*)mapView viewForAnnotation:(id)annotation{//由于當(dāng)前位置的標(biāo)注也是一個(gè)大頭針,所以此時(shí)需要判斷,此代理方法返回nil使用默認(rèn)大頭針視圖if([annotation isKindOfClass:[KCAnnotationclass]]) {staticNSString*key1=@"AnnotationKey1";MKAnnotationView*annotationView=[_mapView dequeueReusableAnnotationViewWithIdentifier:key1];//如果緩存池中不存在則新建if(!annotationView) {? ? ? ? ? ? annotationView=[[MKAnnotationViewalloc]initWithAnnotation:annotation reuseIdentifier:key1];? ? ? ? ? ? annotationView.canShowCallout=true;//允許交互點(diǎn)擊annotationView.calloutOffset=CGPointMake(0,1);//定義詳情視圖偏移量annotationView.leftCalloutAccessoryView=[[UIImageViewalloc]initWithImage:[UIImageimageNamed:@"icon_classify_cafe.png"]];//定義詳情左側(cè)視圖}//修改大頭針視圖//重新設(shè)置此類大頭針視圖的大頭針模型(因?yàn)橛锌赡苁菑木彺娉刂腥〕鰜淼模恢檬欠诺骄彺娉貢r(shí)的位置)annotationView.annotation=annotation;? ? ? ? annotationView.image=((KCAnnotation *)annotation).image;//設(shè)置大頭針視圖的圖片returnannotationView;? ? }else{returnnil;? ? }}@end
運(yùn)行效果:
注意: 在MapKit框架中除了MKAnnotationView之外還有一個(gè)MKPinAnnotationView,它是MKAnnotationView的子類,相比MKAnnotationView多了兩個(gè)屬性pinColor和animationDrop,分別用于設(shè)置大頭針視圖顏色和添加大頭針動(dòng)畫。
擴(kuò)展--自定義大頭針彈詳情視圖
通過上面的示例不難看出MKAnnotationView足夠強(qiáng)大(何況還有MKPinAnnotationView),很多信息都可以進(jìn)行設(shè)置,但是唯獨(dú)不能修改大頭針描述詳情視圖(僅僅支持詳情中左右視圖內(nèi)容)。要實(shí)現(xiàn)這個(gè)需求目前開發(fā)中普遍采用的思路就是:
a.點(diǎn)擊一個(gè)大頭針A時(shí)重新在A的坐標(biāo)處添加另一個(gè)大頭針B(注意此時(shí)將A對(duì)應(yīng)的大頭針視圖canShowCallout設(shè)置為false)作為大頭針詳情模型,然后在- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id )annotation;代理方法中判斷大頭針類型,如果是B則重寫MKAnnotationView(可以自定義一個(gè)類C繼承于MKAnnotationView),返回自定義大頭針視圖C。
b.定義大頭針視圖C繼承于MKAnnotationView(或者M(jìn)KPinAnnotationView),在自定義大頭針視圖中添加自己的控件,完成自定義布局。
在使用百度地圖客戶端時(shí)當(dāng)點(diǎn)擊一個(gè)搜索位置時(shí)可以看到此位置的評(píng)價(jià)等信息,視圖效果大概如下:
下面不妨試著實(shí)現(xiàn)一下這個(gè)效果:
大頭針模型:KCAnnotation.h
////? KCAnnotation.h//? MapKit////? Created by Kenshin Cui on 14/3/27.//? Copyright (c) 2014年 Kenshin Cui. All rights reserved.//#import#import@interfaceKCAnnotation:NSObject@property(nonatomic)CLLocationCoordinate2Dcoordinate;@property(nonatomic,copy)NSString*title;@property(nonatomic,copy)NSString*subtitle;#pragma mark 自定義一個(gè)圖片屬性在創(chuàng)建大頭針視圖時(shí)使用@property(nonatomic,strong)UIImage*image;#pragma mark 大頭針詳情左側(cè)圖標(biāo)@property(nonatomic,strong)UIImage*icon;#pragma mark 大頭針詳情描述@property(nonatomic,copy)NSString*detail;#pragma mark 大頭針右下方星級(jí)評(píng)價(jià)@property(nonatomic,strong)UIImage*rate;@end
彈出詳情大頭針模型:KCCalloutAnnotation.h
////? KCCalloutAnnotation.h//? MapKit////? Created by Kenshin Cui on 14/3/27.//? Copyright (c) 2014年 Kenshin Cui. All rights reserved.//#import#import#import@interfaceKCCalloutAnnotation:NSObject@property(nonatomic)CLLocationCoordinate2Dcoordinate;@property(nonatomic,copy,readonly)NSString*title;@property(nonatomic,copy,readonly)NSString*subtitle;#pragma mark 左側(cè)圖標(biāo)@property(nonatomic,strong)UIImage*icon;#pragma mark 詳情描述@property(nonatomic,copy)NSString*detail;#pragma mark 星級(jí)評(píng)價(jià)@property(nonatomic,strong)UIImage*rate;@end
彈出詳情大頭針視圖:KCCalloutAnnotatonView.h
////? KCCalloutView.h//? MapKit////? Created by Kenshin Cui on 14/3/27.//? Copyright (c) 2014年 Kenshin Cui. All rights reserved.//? 自定義彈出標(biāo)注視圖#import#import#import#import"KCCalloutAnnotation.h"@interfaceKCCalloutAnnotationView:MKAnnotationView@property(nonatomic,strong) KCCalloutAnnotation *annotation;#pragma mark 從緩存取出標(biāo)注視圖+(instancetype)calloutViewWithMapView:(MKMapView*)mapView;@end
KCCalloutAnnotationView.m
////? KCCalloutView.m//? MapKit////? Created by Kenshin Cui on 14/3/27.//? Copyright (c) 2014年 Kenshin Cui. All rights reserved.//#import"KCCalloutAnnotationView.h"#define kSpacing 5#define kDetailFontSize 12#define kViewOffset 80@interfaceKCCalloutAnnotationView(){UIView*_backgroundView;UIImageView*_iconView;UILabel*_detailLabel;UIImageView*_rateView;}@end@implementationKCCalloutAnnotationView-(instancetype)init{if(self=[superinit]){? ? ? ? [selflayoutUI];? ? }returnself;}-(instancetype)initWithFrame:(CGRect)frame{if(self=[superinitWithFrame:frame]) {? ? ? ? [selflayoutUI];? ? }returnself;}-(void)layoutUI{//背景_backgroundView=[[UIViewalloc]init];? ? _backgroundView.backgroundColor=[UIColorwhiteColor];//左側(cè)添加圖標(biāo)_iconView=[[UIImageViewalloc]init];//上方詳情_detailLabel=[[UILabelalloc]init];? ? _detailLabel.lineBreakMode=NSLineBreakByWordWrapping;//[_text sizeToFit];_detailLabel.font=[UIFontsystemFontOfSize:kDetailFontSize];//下方星級(jí)_rateView=[[UIImageViewalloc]init];? ? ? ? [selfaddSubview:_backgroundView];? ? [selfaddSubview:_iconView];? ? [selfaddSubview:_detailLabel];? ? [selfaddSubview:_rateView];}+(instancetype)calloutViewWithMapView:(MKMapView*)mapView{staticNSString*calloutKey=@"calloutKey1";? ? KCCalloutAnnotationView *calloutView=(KCCalloutAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:calloutKey];if(!calloutView) {? ? ? ? calloutView=[[KCCalloutAnnotationView alloc]init];? ? }returncalloutView;}#pragma mark 當(dāng)給大頭針視圖設(shè)置大頭針模型時(shí)可以在此處根據(jù)模型設(shè)置視圖內(nèi)容-(void)setAnnotation:(KCCalloutAnnotation *)annotation{? ? [supersetAnnotation:annotation];//根據(jù)模型調(diào)整布局_iconView.image=annotation.icon;? ? _iconView.frame=CGRectMake(kSpacing, kSpacing, annotation.icon.size.width, annotation.icon.size.height);? ? ? ? _detailLabel.text=annotation.detail;floatdetailWidth=150.0;CGSizedetailSize= [annotation.detail boundingRectWithSize:CGSizeMake(detailWidth, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOriginattributes:@{NSFontAttributeName: [UIFontsystemFontOfSize:kDetailFontSize]} context:nil].size;floatdetailX=CGRectGetMaxX(_iconView.frame)+kSpacing;? ? _detailLabel.frame=CGRectMake(detailX, kSpacing, detailSize.width, detailSize.height);? ? _rateView.image=annotation.rate;? ? _rateView.frame=CGRectMake(detailX,CGRectGetMaxY(_detailLabel.frame)+kSpacing, annotation.rate.size.width, annotation.rate.size.height);floatbackgroundWidth=CGRectGetMaxX(_detailLabel.frame)+kSpacing;floatbackgroundHeight=_iconView.frame.size.height+2*kSpacing;? ? _backgroundView.frame=CGRectMake(0,0, backgroundWidth, backgroundHeight);self.bounds=CGRectMake(0,0, backgroundWidth, backgroundHeight+kViewOffset);? ? }@end
主視圖控制器:KCMainViewController.m
////? KCMainViewController.m//? MapKit Annotation////? Created by Kenshin Cui on 14/3/27.//? Copyright (c) 2014年 Kenshin Cui. All rights reserved.//? 37.785834? -122.406417//? 39.92 116.39#import"KCMainViewController.h"#import#import#import"KCAnnotation.h"#import"KCCalloutAnnotationView.h"#import"KCCalloutAnnotationView.h"@interfaceKCMainViewController(){CLLocationManager*_locationManager;MKMapView*_mapView;}@end@implementationKCMainViewController- (void)viewDidLoad {? ? [superviewDidLoad];? ? ? ? [selfinitGUI];}#pragma mark 添加地圖控件-(void)initGUI{CGRectrect=[UIScreenmainScreen].bounds;? ? _mapView=[[MKMapViewalloc]initWithFrame:rect];? ? [self.view addSubview:_mapView];//設(shè)置代理_mapView.delegate=self;//請(qǐng)求定位服務(wù)_locationManager=[[CLLocationManageralloc]init];if(![CLLocationManagerlocationServicesEnabled]||[CLLocationManagerauthorizationStatus]!=kCLAuthorizationStatusAuthorizedWhenInUse){? ? ? ? [_locationManager requestWhenInUseAuthorization];? ? }//用戶位置追蹤(用戶位置追蹤用于標(biāo)記用戶當(dāng)前位置,此時(shí)會(huì)調(diào)用定位服務(wù))_mapView.userTrackingMode=MKUserTrackingModeFollow;//設(shè)置地圖類型_mapView.mapType=MKMapTypeStandard;//添加大頭針[selfaddAnnotation];}#pragma mark 添加大頭針-(void)addAnnotation{CLLocationCoordinate2Dlocation1=CLLocationCoordinate2DMake(39.95,116.35);? ? KCAnnotation *annotation1=[[KCAnnotation alloc]init];? ? annotation1.title=@"CMJ Studio";? ? annotation1.subtitle=@"Kenshin Cui's Studios";? ? annotation1.coordinate=location1;? ? annotation1.image=[UIImageimageNamed:@"icon_pin_floating.png"];? ? annotation1.icon=[UIImageimageNamed:@"icon_mark1.png"];? ? annotation1.detail=@"CMJ Studio...";? ? annotation1.rate=[UIImageimageNamed:@"icon_Movie_Star_rating.png"];? ? [_mapView addAnnotation:annotation1];CLLocationCoordinate2Dlocation2=CLLocationCoordinate2DMake(39.87,116.35);? ? KCAnnotation *annotation2=[[KCAnnotation alloc]init];? ? annotation2.title=@"Kenshin&Kaoru";? ? annotation2.subtitle=@"Kenshin Cui's Home";? ? annotation2.coordinate=location2;? ? annotation2.image=[UIImageimageNamed:@"icon_paopao_waterdrop_streetscape.png"];? ? annotation2.icon=[UIImageimageNamed:@"icon_mark2.png"];? ? annotation2.detail=@"Kenshin Cui...";? ? annotation2.rate=[UIImageimageNamed:@"icon_Movie_Star_rating.png"];? ? [_mapView addAnnotation:annotation2];}#pragma mark - 地圖控件代理方法#pragma mark 顯示大頭針時(shí)調(diào)用,注意方法中的annotation參數(shù)是即將顯示的大頭針對(duì)象-(MKAnnotationView*)mapView:(MKMapView*)mapView viewForAnnotation:(id)annotation{//由于當(dāng)前位置的標(biāo)注也是一個(gè)大頭針,所以此時(shí)需要判斷,此代理方法返回nil使用默認(rèn)大頭針視圖if([annotation isKindOfClass:[KCAnnotationclass]]) {staticNSString*key1=@"AnnotationKey1";MKAnnotationView*annotationView=[_mapView dequeueReusableAnnotationViewWithIdentifier:key1];//如果緩存池中不存在則新建if(!annotationView) {? ? ? ? ? ? annotationView=[[MKAnnotationViewalloc]initWithAnnotation:annotation reuseIdentifier:key1];//? ? ? ? ? ? annotationView.canShowCallout=true;//允許交互點(diǎn)擊annotationView.calloutOffset=CGPointMake(0,1);//定義詳情視圖偏移量annotationView.leftCalloutAccessoryView=[[UIImageViewalloc]initWithImage:[UIImageimageNamed:@"icon_classify_cafe.png"]];//定義詳情左側(cè)視圖}//修改大頭針視圖//重新設(shè)置此類大頭針視圖的大頭針模型(因?yàn)橛锌赡苁菑木彺娉刂腥〕鰜淼模恢檬欠诺骄彺娉貢r(shí)的位置)annotationView.annotation=annotation;? ? ? ? annotationView.image=((KCAnnotation *)annotation).image;//設(shè)置大頭針視圖的圖片returnannotationView;? ? }elseif([annotation isKindOfClass:[KCCalloutAnnotationclass]]){//對(duì)于作為彈出詳情視圖的自定義大頭針視圖無彈出交互功能(canShowCallout=false,這是默認(rèn)值),在其中可以自由添加其他視圖(因?yàn)樗旧砝^承于UIView)KCCalloutAnnotationView *calloutView=[KCCalloutAnnotationView calloutViewWithMapView:mapView];? ? ? ? calloutView.annotation=annotation;returncalloutView;? ? }else{returnnil;? ? }}#pragma mark 選中大頭針時(shí)觸發(fā)//點(diǎn)擊一般的大頭針KCAnnotation時(shí)添加一個(gè)大頭針作為所點(diǎn)大頭針的彈出詳情視圖-(void)mapView:(MKMapView*)mapView didSelectAnnotationView:(MKAnnotationView*)view{? ? KCAnnotation *annotation=view.annotation;if([view.annotation isKindOfClass:[KCAnnotationclass]]) {//點(diǎn)擊一個(gè)大頭針時(shí)移除其他彈出詳情視圖//? ? ? ? [self removeCustomAnnotation];//添加詳情大頭針,渲染此大頭針視圖時(shí)將此模型對(duì)象賦值給自定義大頭針視圖完成自動(dòng)布局KCCalloutAnnotation *annotation1=[[KCCalloutAnnotation alloc]init];? ? ? ? annotation1.icon=annotation.icon;? ? ? ? annotation1.detail=annotation.detail;? ? ? ? annotation1.rate=annotation.rate;? ? ? ? annotation1.coordinate=view.annotation.coordinate;? ? ? ? [mapView addAnnotation:annotation1];? ? }}#pragma mark 取消選中時(shí)觸發(fā)-(void)mapView:(MKMapView*)mapView didDeselectAnnotationView:(MKAnnotationView*)view{? ? [selfremoveCustomAnnotation];}#pragma mark 移除所用自定義大頭針-(void)removeCustomAnnotation{? ? [_mapView.annotations enumerateObjectsUsingBlock:^(idobj,NSUIntegeridx,BOOL*stop) {if([obj isKindOfClass:[KCCalloutAnnotationclass]]) {? ? ? ? ? ? [_mapView removeAnnotation:obj];? ? ? ? }? ? }];}@end
在這個(gè)過程中需要注意幾點(diǎn):
1.大頭針A作為一個(gè)普通大頭針,其中最好保存自定義大頭針視圖C所需要的模型以便根據(jù)不同的模型初始化視圖。
2.自定義大頭針視圖C的大頭針模型B中不需要title、subtitle屬性,最好設(shè)置為只讀;模型中最后保存自定義大頭針視圖C所需要的布局模型數(shù)據(jù)。
3.只有點(diǎn)擊非B類大頭針時(shí)才新增自定義大頭針,并且增加時(shí)要首先移除其他B類大頭針避免重疊(一般建議放到取消大頭針選擇的代理方法中)。
4.通常在自定義大頭針視圖C設(shè)置大頭針模型時(shí)布局界面,此時(shí)需要注意新增大頭針的位置,通常需要偏移一定的距離才能達(dá)到理想的效果。
運(yùn)行效果:
使用自帶的地圖應(yīng)用
除了可以使用MapKit框架進(jìn)行地圖開發(fā),對(duì)地圖有精確的控制和自定義之外,如果對(duì)于應(yīng)用沒有特殊要求的話選用蘋果自帶的地圖應(yīng)用也是一個(gè)不錯(cuò)的選擇。使用蘋果自帶的應(yīng)用時(shí)需要用到MapKit中的MKMapItem類,這個(gè)類有一個(gè)openInMapsWithLaunchOptions:動(dòng)態(tài)方法和一個(gè)openMapsWithItems: launchOptions:靜態(tài)方法用于打開蘋果地圖應(yīng)用。第一個(gè)方法用于在地圖上標(biāo)注一個(gè)位置,第二個(gè)方法除了可以標(biāo)注多個(gè)位置外還可以進(jìn)行多個(gè)位置之間的駕駛導(dǎo)航,使用起來也是相當(dāng)方便。在熟悉這兩個(gè)方法使用之前有必要對(duì)兩個(gè)方法中的options參數(shù)做一下簡(jiǎn)單說明:
鍵(常量)說明值
MKLaunchOptionsDirectionsModeKey
路線模式,常量
MKLaunchOptionsDirectionsModeDriving ?駕車模式
MKLaunchOptionsDirectionsModeWalking 步行模式
MKLaunchOptionsMapTypeKey
地圖類型,枚舉
MKMapTypeStandard :標(biāo)準(zhǔn)模式
MKMapTypeSatellite :衛(wèi)星模式
MKMapTypeHybrid ?:混合模式
MKLaunchOptionsMapCenterKey
中心點(diǎn)坐標(biāo),CLLocationCoordinate2D類型
MKLaunchOptionsMapSpanKey
地圖顯示跨度,MKCoordinateSpan 類型
MKLaunchOptionsShowsTrafficKey
是否 顯示交通狀況,布爾型
MKLaunchOptionsCameraKey
3D地圖效果,MKMapCamera類型
注意:此屬性從iOS7及以后可用,前面的屬性從iOS6開始可用
單個(gè)位置的標(biāo)注
下面的代碼演示了如何在蘋果自帶地圖應(yīng)用上標(biāo)記一個(gè)位置,首先根據(jù)反地理編碼獲得一個(gè)CLPlacemark位置對(duì)象,然后將其轉(zhuǎn)換為MKPlacemark對(duì)象用于MKMapItem初始化,最后調(diào)用其openInMapsWithLaunchOptions:打開地圖應(yīng)用并標(biāo)記:
////? KCMainViewController.m//? AppleMap////? Created by Kenshin Cui on 14/3/27.//? Copyright (c) 2014年 Kenshin Cui. All rights reserved.//#import"KCMainViewController.h"#import#import@interfaceKCMainViewController()@property(nonatomic,strong)CLGeocoder*geocoder;@end@implementationKCMainViewController- (void)viewDidLoad {? ? [superviewDidLoad];? ? ? ? _geocoder=[[CLGeocoderalloc]init];? ? ? ? [selflocation];}#pragma mark 在地圖上定位-(void)location{//根據(jù)“北京市”進(jìn)行地理編碼[_geocoder geocodeAddressString:@"北京市"completionHandler:^(NSArray*placemarks,NSError*error) {CLPlacemark*clPlacemark=[placemarks firstObject];//獲取第一個(gè)地標(biāo)MKPlacemark*mkplacemark=[[MKPlacemarkalloc]initWithPlacemark:clPlacemark];//定位地標(biāo)轉(zhuǎn)化為地圖的地標(biāo)NSDictionary*options=@{MKLaunchOptionsMapTypeKey:@(MKMapTypeStandard)};MKMapItem*mapItem=[[MKMapItemalloc]initWithPlacemark:mkplacemark];? ? ? ? [mapItem openInMapsWithLaunchOptions:options];? ? }];}@end
運(yùn)行效果:
標(biāo)記多個(gè)位置
如果要標(biāo)記多個(gè)位置需要調(diào)用MKMapItem的靜態(tài)方法,下面的代碼演示中需要注意,使用CLGeocoder進(jìn)行定位時(shí)一次只能定位到一個(gè)位置,所以第二個(gè)位置定位放到了第一個(gè)位置獲取成功之后。
////? KCMainViewController.m//? AppleMap////? Created by Kenshin Cui on 14/3/27.//? Copyright (c) 2014年 Kenshin Cui. All rights reserved.//#import"KCMainViewController.h"#import#import@interfaceKCMainViewController()@property(nonatomic,strong)CLGeocoder*geocoder;@end@implementationKCMainViewController- (void)viewDidLoad {? ? [superviewDidLoad];? ? ? ? _geocoder=[[CLGeocoderalloc]init];? ? ? ? [selflistPlacemark];}-(void)listPlacemark{//根據(jù)“北京市”進(jìn)行地理編碼[_geocoder geocodeAddressString:@"北京市"completionHandler:^(NSArray*placemarks,NSError*error) {CLPlacemark*clPlacemark1=[placemarks firstObject];//獲取第一個(gè)地標(biāo)MKPlacemark*mkPlacemark1=[[MKPlacemarkalloc]initWithPlacemark:clPlacemark1];//注意地理編碼一次只能定位到一個(gè)位置,不能同時(shí)定位,所在放到第一個(gè)位置定位完成回調(diào)函數(shù)中再次定位[_geocoder geocodeAddressString:@"鄭州市"completionHandler:^(NSArray*placemarks,NSError*error) {CLPlacemark*clPlacemark2=[placemarks firstObject];//獲取第一個(gè)地標(biāo)MKPlacemark*mkPlacemark2=[[MKPlacemarkalloc]initWithPlacemark:clPlacemark2];NSDictionary*options=@{MKLaunchOptionsMapTypeKey:@(MKMapTypeStandard)};//MKMapItem *mapItem1=[MKMapItem mapItemForCurrentLocation];//當(dāng)前位置MKMapItem*mapItem1=[[MKMapItemalloc]initWithPlacemark:mkPlacemark1];MKMapItem*mapItem2=[[MKMapItemalloc]initWithPlacemark:mkPlacemark2];? ? ? ? ? ? [MKMapItemopenMapsWithItems:@[mapItem1,mapItem2] launchOptions:options];? ? ? ? ? ? ? ? ? ? }];? ? ? ? ? ? }];}@end
運(yùn)行效果:
地圖導(dǎo)航
要使用地圖導(dǎo)航功能在自帶地圖應(yīng)用中相當(dāng)簡(jiǎn)單,只要設(shè)置參數(shù)配置導(dǎo)航模式即可,例如在上面代碼基礎(chǔ)上設(shè)置駕駛模式,則地圖應(yīng)用會(huì)啟動(dòng)駕駛模式計(jì)算兩點(diǎn)之間的距離同時(shí)對(duì)路線進(jìn)行規(guī)劃。
////? KCMainViewController.m//? AppleMap////? Created by Kenshin Cui on 14/3/27.//? Copyright (c) 2014年 Kenshin Cui. All rights reserved.//#import"KCMainViewController.h"#import#import@interfaceKCMainViewController()@property(nonatomic,strong)CLGeocoder*geocoder;@end@implementationKCMainViewController- (void)viewDidLoad {? ? [superviewDidLoad];? ? ? ? _geocoder=[[CLGeocoderalloc]init];? ? ? ? [selfturnByTurn];}-(void)turnByTurn{//根據(jù)“北京市”地理編碼[_geocoder geocodeAddressString:@"北京市"completionHandler:^(NSArray*placemarks,NSError*error) {CLPlacemark*clPlacemark1=[placemarks firstObject];//獲取第一個(gè)地標(biāo)MKPlacemark*mkPlacemark1=[[MKPlacemarkalloc]initWithPlacemark:clPlacemark1];//注意地理編碼一次只能定位到一個(gè)位置,不能同時(shí)定位,所在放到第一個(gè)位置定位完成回調(diào)函數(shù)中再次定位[_geocoder geocodeAddressString:@"鄭州市"completionHandler:^(NSArray*placemarks,NSError*error) {CLPlacemark*clPlacemark2=[placemarks firstObject];//獲取第一個(gè)地標(biāo)MKPlacemark*mkPlacemark2=[[MKPlacemarkalloc]initWithPlacemark:clPlacemark2];NSDictionary*options=@{MKLaunchOptionsMapTypeKey:@(MKMapTypeStandard),MKLaunchOptionsDirectionsModeKey:MKLaunchOptionsDirectionsModeDriving};//MKMapItem *mapItem1=[MKMapItem mapItemForCurrentLocation];//當(dāng)前位置MKMapItem*mapItem1=[[MKMapItemalloc]initWithPlacemark:mkPlacemark1];MKMapItem*mapItem2=[[MKMapItemalloc]initWithPlacemark:mkPlacemark2];? ? ? ? ? ? [MKMapItemopenMapsWithItems:@[mapItem1,mapItem2] launchOptions:options];? ? ? ? ? ? ? ? ? ? }];? ? ? ? ? ? }];}@end
運(yùn)行效果:
注意:其實(shí)如果不用蘋果自帶的地圖應(yīng)用也可以實(shí)現(xiàn)地圖導(dǎo)航,MapKit中提供了MKDirectionRequest對(duì)象用于計(jì)算路線,提供了MKDirections用于計(jì)算方向,這樣一來只需要調(diào)用MKMapView的addOverlay等方法添加覆蓋物即可實(shí)現(xiàn)類似的效果,有興趣的朋友可以試一下。
由于定位和地圖框架中用到了諸多類,有些初學(xué)者容易混淆,下面簡(jiǎn)單對(duì)比一下。
CLLocation:用于表示位置信息,包含地理坐標(biāo)、海拔等信息,包含在CoreLoaction框架中。
MKUserLocation:一個(gè)特殊的大頭針,表示用戶當(dāng)前位置。
CLPlacemark:定位框架中地標(biāo)類,封裝了詳細(xì)的地理信息。
MKPlacemark:類似于CLPlacemark,只是它在MapKit框架中,可以根據(jù)CLPlacemark創(chuàng)建MKPlacemark。