iOS陸哥開發筆記(五) (地圖定位之官方API)
定位
要實現地圖、導航功能,往往需要先熟悉定位功能,在iOS中通過Core Location架構進行定位操作。Core Location自身可以單獨使用,和地圖開發架構MapKit完全是獨立的,但是往往地圖開發要配合定位架構使用。在Core Location中主要包含了定位、地理編碼(包括反編碼)功能。
定位功能
定位是一個很常用的功能,如一些地圖軟體開啟之後如果使用者允許軟體定位的話,那麼開啟軟體後就會自動鎖定到當前位置,如果使用者手機移動那麼當前位置也會跟隨著變化。要實現這個功能需要使用Core Loaction中CLLocationManager類,首先看一下這個類的一些主要方法和屬性:
類方法 |
說明 |
+ (BOOL)locationServicesEnabled; |
是否啟用定位服務,通常如果使用者沒有啟用定位服務可以提示使用者開啟定位服務 |
+ (CLAuthorizationStatus)authorizationStatus; |
定位服務授權狀態,返回枚舉類型: kCLAuthorizationStatusNotDetermined: 使用者尚未做出決定是否啟用定位服務 kCLAuthorizationStatusRestricted: 沒有獲得使用者授權使用定位服務,可能使用者沒有自己禁止訪問授權 kCLAuthorizationStatusDenied :使用者已經明確禁止應用使用定位服務或者當前系統定位服務處於關閉狀態 kCLAuthorizationStatusAuthorizedAlways: 應用獲得授權可以一直使用定位服務,即使應用不在使用狀態 kCLAuthorizationStatusAuthorizedWhenInUse: 使用此應用過程中允許訪問定位服務 |
屬性 |
說明 |
desiredAccuracy |
定位精度,枚舉類型:
kCLLocationAccuracyBest:最精確定位 CLLocationAccuracy kCLLocationAccuracyNearestTenMeters:十米誤差範圍 kCLLocationAccuracyHundredMeters:百米誤差範圍 kCLLocationAccuracyKilometer:千米誤差範圍 kCLLocationAccuracyThreeKilometers:三千米誤差範圍 |
distanceFilter |
位置資訊更新最小距離,只有移動大於這個距離才更新位置資訊,預設為kCLDistanceFilterNone:不進行距離限制 |
對象方法 |
說明 |
startUpdatingLocation |
開始定位追蹤,開始定位後將按照使用者佈建的更新頻率執行-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations;方法反饋定位資訊 |
stopUpdatingLocation |
停止定位追蹤 |
startUpdatingHeading |
開始導航方向追蹤 |
stopUpdatingHeading |
停止導航方向追蹤 |
startMonitoringForRegion: |
開始對某個地區進行定位追蹤,開始對某個地區進行定位後。如果使用者進入或者走出某個地區會調用- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region和- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region代理方法反饋相關資訊 |
stopMonitoringForRegion: |
停止對某個地區進行定位追蹤 |
requestWhenInUseAuthorization |
請求獲得應用使用時的定位服務授權,注意使用此方法前在要在info.plist中配置NSLocationWhenInUseUsageDescription |
requestAlwaysAuthorization |
請求獲得應用一直使用定位服務授權,注意使用此方法前要在info.plist中配置NSLocationAlwaysUsageDescription |
代理方法 |
說明 |
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations; |
位置發生改變後執行(第一次定位到某個位置之後也會執行) |
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading; |
導航方向發生變化後執行 |
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region |
進入某個地區之後執行 |
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region |
走出某個地區之後執行 |
iOS 8 還提供了更加人性化的定位服務選項。App 的定位服務不再僅僅是關閉或開啟,現在,定位服務的啟用提供了三個選項,「永不」「使用應用程式期間」和「始終」。同時,考慮到能耗問題,如果一款 App 要求始終能在後台開啟定位服務,iOS 8 不僅會在首次開啟 App 時主動向你詢問,還會在日常使用中彈窗提醒你該 App 一直在後台使用定位服務,並詢問你是否繼續允許。在iOS7及以前的版本,如果在應用程式中使用定位服務只要在程式中調用startUpdatingLocation方法應用就會詢問使用者是否允許此應用是否允許使用定位服務,同時在提示過程中可以通過在info.plist中配置通過配置Privacy - Location Usage Description告訴使用者使用的目的,同時這個配置是可選的。
但是在iOS8中配置配置項發生了變化,可以通過配置NSLocationAlwaysUsageDescription或者NSLocationWhenInUseUsageDescription來告訴使用者使用定位服務的目的,並且注意這個配置是必須的,如果不進行配置則預設情況下應用無法使用定位服務,開啟應用不會給出開啟定位服務的提示,除非安裝後自己設定此應用的定位服務。同時,在應用程式中需要根據配置對requestAlwaysAuthorization或locationServicesEnabled方法進行請求。由於本人機器已經更新到最新的iOS8.1下面的內容主要針對iOS8,使用iOS7的朋友需要稍作調整。
注意:
1.定位頻率和定位精度並不應當越精確越好,需要視實際情況而定,因為越精確越耗效能,也就越費電。
2.定位成功後會根據設定情況頻繁調用-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations方法,這個方法返回一組地理位置對象數組,每個元素一個CLLocation代表地理位置資訊(包含經度、緯度、海報、行走速度等資訊),之所以返回數組是因為有些時候一個位置點可能包含多個位置。
3.使用完定位服務後如果不需要即時監控應該立即關閉定位服務以節省資源。
4.除了提供定位功能,CLLocationManager還可以調用startMonitoringForRegion:方法對指定地區進行監控。
在iOS中進行地圖開發主要有兩種方式,一種是直接利用MapKit架構進行地圖開發,利用這種方式可以對地圖進行精準的控制;另一種方式是直接調用蘋果官方內建的地圖應用,主要用於一些簡單的地圖應用(例如:進行導航覆蓋物填充等),無法進行精確的控制。當然,本節重點內容還是前者,後面的內容也會稍加提示。
用MapKit之前需要簡單瞭解一下MapKit中地圖展示控制項MKMapView的的一些常用屬性和方法,具體如下表:
屬性 |
說明 |
userTrackingMode |
跟蹤類型,是一個枚舉: MKUserTrackingModeNone :不進行使用者位置跟蹤; MKUserTrackingModeFollow :跟蹤使用者位置; MKUserTrackingModeFollowWithHeading :跟蹤使用者位置並且跟蹤使用者前進方向; |
mapType |
地圖類型,是一個枚舉: MKMapTypeStandard :標準地圖,一般情況下使用此地圖即可滿足; MKMapTypeSatellite :衛星地圖; MKMapTypeHybrid :混合地圖,載入最慢比較消耗資源; |
userLocation |
使用者位置,唯讀屬性 |
annotations |
當前地圖中的所有圖釘,唯讀屬性 |
對象方法 |
說明 |
- (void)addAnnotation:(id )annotation; |
添加圖釘,對應的有添加圖釘數組 |
- (void)removeAnnotation:(id )annotation; |
刪除圖釘,對應的有刪除圖釘數組 |
- (void)setRegion:(MKCoordinateRegion)region animated:(BOOL)animated; |
設定地圖顯示地區,用於控制當前螢幕顯示地圖範圍 |
- (void)setCenterCoordinate:(CLLocationCoordinate2D)coordinate animated:(BOOL)animated; |
設定地圖中心點位置 |
- (CGPoint)convertCoordinate:(CLLocationCoordinate2D)coordinate toPointToView:(UIView *)view; |
將地理座標(經緯度)轉化為數學座標(UIKit座標) |
- (CLLocationCoordinate2D)convertPoint:(CGPoint)point toCoordinateFromView:(UIView *)view; |
將數學座標轉換為地理座標 |
- (MKAnnotationView *)dequeueReusableAnnotationViewWithIdentifier:(NSString *)identifier; |
從緩衝池中取出圖釘,類似於UITableView中取出UITableViewCell,為了進行效能最佳化而設計 |
- (void)selectAnnotation:(id )annotation animated:(BOOL)animated; |
選中指定的圖釘 |
- (void)deselectAnnotation:(id )annotation animated:(BOOL)animated; |
取消選中指定的圖釘 |
代理方法 |
說明 |
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation ; |
使用者位置發生改變時觸發(第一次定位到使用者位置也會觸發該方法) |
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation ; |
顯示地區發生改變後觸發 |
- (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView; |
地圖載入完成後觸發 |
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id )annotation; |
顯示圖釘時觸發,返回圖釘視圖,通常自訂圖釘可以通過此方法進行 |
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view |
點擊選中某個圖釘時觸發 |
- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view |
取消選中圖釘時觸發 |
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id )overlay |
渲染地圖覆蓋物時觸發 |
設定圖釘視圖
在一些應用中系統預設的圖釘樣式可能無法滿足實際的需求,此時就需要修改圖釘視圖預設樣式。根據前面MapKit的代理方法不難發現- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id )annotation;方法可以返回一個圖釘視圖,只要實現這個方法並在這個方法中定義一個圖釘視圖MKAnnotationView對象並設定相關屬性就可以改變預設圖釘的樣式。MKAnnotationView常用屬性:
屬性 |
說明 |
annotation |
圖釘模型資訊,包括標題、子標題、地理位置。 |
image |
圖釘圖片 |
canShowCallout |
點擊圖釘是否顯示標題、子標題內容等,注意如果在- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id )annotation;方法中重新定義圖釘預設情況是無法互動的需要設定為true。 |
calloutOffset |
點擊圖釘時彈出詳情資訊視圖的位移量 |
selected |
是否被選中狀態 |
leftCalloutAccessoryView |
彈出詳情左側視圖 |
rightCalloutAccessoryView |
彈出詳情右側視圖 |
需要注意:
a.這個代理方法的調用時機:每當有圖釘顯示到系統視覺化介面中時就會調用此方法返回一個圖釘視圖放到介面中,同時當前系統位置標註(也就是地圖中藍色的位置點)也是一個圖釘,也會調用此方法,因此處理圖釘視圖時需要區別對待。
b.類似於UITableView的代理方法,此方法調用頻繁,開發過程中需要重複利用MapKit的緩衝池將圖釘視圖緩衝起來重複利用。
c.自訂圖釘預設情況下不允許互動,如果互動需要設定canShowCallout=true
d.如果代理方法返回nil則會使用預設圖釘視圖,需要根據情況設定。
使用內建的地圖應用
除了可以使用MapKit架構進行地圖開發,對地圖有精確的控制和自訂之外,如果對於應用沒有特殊要求的話選用蘋果內建的地圖應用也是一個不錯的選擇。使用蘋果內建的應用時需要用到MapKit中的MKMapItem類,這個類有一個openInMapsWithLaunchOptions:動態方法和一個openMapsWithItems: launchOptions:靜態方法用於開啟蘋果地圖應用。第一個方法用於在地圖上標註一個位置,第二個方法除了可以標註多個位置外還可以進行多個位置之間的駕駛導航,使用起來也是相當方便。在熟悉這兩個方法使用之前有必要對兩個方法中的options參數做一下簡單說明:
鍵(常量) |
說明 |
值 |
MKLaunchOptionsDirectionsModeKey |
路線模式,常量 |
MKLaunchOptionsDirectionsModeDriving 駕車模式 MKLaunchOptionsDirectionsModeWalking 步行模式 |
MKLaunchOptionsMapTypeKey |
地圖類型,枚舉 |
MKMapTypeStandard :標準模式 MKMapTypeSatellite :衛星模式 MKMapTypeHybrid :混合模式 |
MKLaunchOptionsMapCenterKey |
中心點座標,CLLocationCoordinate2D類型 |
|
MKLaunchOptionsMapSpanKey |
地圖顯示跨度,MKCoordinateSpan 類型 |
|
MKLaunchOptionsShowsTrafficKey |
是否 顯示交通狀況,布爾型 |
|
MKLaunchOptionsCameraKey |
3D地圖效果,MKMapCamera類型 注意:此屬性從iOS7及以後可用,前面的屬性從iOS6開始可用 |
|
有些初學者容易混淆,下面簡單對比一下。
CLLocation:用於表示位置資訊,包含地理座標、海拔等資訊,包含在CoreLoaction架構中。
MKUserLocation:一個特殊的圖釘,表示使用者當前位置。
CLPlacemark:定位架構中地標類,封裝了詳細的地理資訊。
MKPlacemark:類似於CLPlacemark,只是它在MapKit架構中,可以根據CLPlacemark建立MKPlacemark。