iOS學習筆記(9)-地圖MapKit入門

這篇文章還是翻譯自raywenderlich,用Objective-C改寫了代碼。沒有逐字翻譯,如有錯漏,請指出。原文地址在這里

1 概述

MapKit是iOS提供的一個很便捷的API,旨在幫助我們快速開發地理位置相關的應用。在這篇博客中涉及的地方叫Honolulu,是美國的一個城市,中文名是檀香山,是美國夏威夷州首府和港口城市。我第一次聽說檀香山應該是在歷史書上,似乎跟孫中山先生相關,這里暫時按下不表。

本文的例子中我們要添加一個地圖到APP中,然后通過經緯度定位到一個指定的位置,通過大頭針的形式來展示定位,點擊大頭針會顯示位置的一些信息。我們可以設置大頭針的顏色,當然我們更可以自定義圖片來替換默認的大頭針,豐富地圖內容。

2 開始

首先新建工程,命名為MapKitTutorial,然后添加一個Map Kit View到Storyboard中。先拖拽地圖視圖到充滿屏幕,然后選擇添加建議的約束即可,添加完約束效果如圖1所示。

圖1 添加 Map Kit View

然后需要在ViewController.m中添加Map View的outlet關聯,通過CTRL+DRAG即可,命名為mapView,代碼如下,別忘記引入MapKit頭文件,注意要先導入MapKit庫(Xcode7.3里面,先選擇工程,然后在Capabilities那一項把Maps開關打開):

......
#import <MapKit/MapKit.h>
@interface ViewController ()
@property (weak, nonatomic) IBOutlet MKMapView *mapView;
@end

這樣,我們編譯運行項目,可以看到地圖出現了,默認顯示的是中國地圖在中央位置,這個應該是跟系統環境相關。如圖2所示:

圖2 地圖視圖

3 設置可視區域

接下來重點來了,我們要設置一個可視區域。學過地理
的都知道(我是地理盲),一個地理位置我們是通過緯度和經度來確定一個位置,緯度中北緯和南緯各分為90度,經度西經和東經則各為180度。在iOS開發中,北緯和東經我們用正數表示,南緯和西經用負數表示。

接下來我們要設置一個可視區域,不設置我們看到的只是一個默認區域,如前面看到的一樣。設置可視區域的代碼如下,然后在方法viewDidLoad中加入調用:

- (void)centerMapOnLocation {
    //1 設置好緯度和經度
    CLLocationCoordinate2D initialLocation = {21.282778, -157.829444}; 
    CLLocationDistance regionRadius = 1000;
    
    MKCoordinateRegion coordinateRegion = MKCoordinateRegionMakeWithDistance(initialLocation, regionRadius * 2, regionRadius * 2);
    [self.mapView setRegion:coordinateRegion];
}

這里來解析一下,首先是設置好中心點的經緯度。然后是設置區域半徑,包括橫向和縱向半徑,這里都設置的為2000米(南北和東西的跨度范圍)。接著根據中心點經緯度和區域半徑創建一個Region,最后調用MapView的setRegion方法即可。這時我們再運行代碼可以看到效果如圖3所示,我們看到與前面不同了,確實地圖已經定位到我們設置的中心點和區域大小了:

圖3 設置可視區域

4 設置標記

接下來來設置一個標記,也就是通常見到的那種大頭針。先新建一個類Artwork來表示標記內容,包括位置坐標,標題和副標題等。位置坐標用于確定大頭針位置,而標題和副標題則是點擊大頭針的時候顯示的內容。

@interface Artwork : NSObject <MKAnnotation>

@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *subtitle;
@property (nonatomic, strong) NSString *locationName;
@property (nonatomic, strong) NSString *discipline;
@property (nonatomic) CLLocationCoordinate2D coordinate;

- (instancetype)init:(NSString *)title 
locationName:(NSString *)locationName
 discipline:(NSString *)discipline 
coordinate:(CLLocationCoordinate2D)coordinate;

@end

類Artwork定義如上所示,然后在ViewController.m中加入添加大頭針的代碼:

- (void)addAnnotation {
    CLLocationCoordinate2D coordinate = {21.283921, -157.831661};
    Artwork *artwork = [[Artwork alloc] init: @"King David Kalakaua"
                          locationName: @"Waikiki Gateway Park"
                          discipline: @"Sculpture"
                          coordinate: coordinate];
    [self.mapView addAnnotation:artwork];
}

注意這里的坐標暫時是自己手動指定,在后面我們會從一個JSON文件中解析一系列的坐標位置然后設置多個大頭針。然后里面的locationName其實是位置名字,而MKAnnotation是一個協議,地圖標記的協議,它里面主要定義了一系列的屬性值(這里可以發現協議不只有方法,也可以定義屬性的),就是標記必須的幾個屬性title,subtitle,coordinate。
然后在viewDidLoad中加入該方法的調用,可以看到大頭針顯示,點擊可以看到title和subtitle的顯示。

圖4 大頭針展示

僅僅這樣當然是不夠的,為了APP的個性化,我們希望可以自定義大頭針顯示方式,可以通過設置ViewController實現協議MKMapViewDelegate,然后將mapView的delegate設置為ViewController,并在ViewController中實現協議的viewForAnnotation方法即可。代碼如下:

- (void)viewDidLoad {
    [super viewDidLoad];
    [self centerMapOnLocation];
    [self addAnnotation];
    //1新增delegate設置
    self.mapView.delegate = self;
}

//2 新增代理方法實現
#pragma MKMapViewDelegate
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
    if ([annotation isKindOfClass:[Artwork class]]) {
        NSString *identifier = @"pin";
        MKPinAnnotationView *view = (MKPinAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
        if (!view) {
            view = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
             //自定義后需要設置canShowCallout為YES,不然點擊不會顯示信息。
            view.canShowCallout = YES;
            //設置信息展示偏移
            view.calloutOffset = CGPointMake(-10, 5);
            //設置信息按鈕
            view.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
        }
        //設置大頭針顏色
        view.pinTintColor = [UIColor blueColor];      
        return view;
    }
    return nil;
}

方法viewForAnnotation中我們定義了大頭針的信息偏移和在顯示內容中添加了一個信息按鈕。偏移位置是針對大頭針的中間頂部而言的,這里我們設置信息展示的X軸向左偏移中間位置10個Point,Y軸則從頂部往下移動5個Point,并將大頭針的顏色設置為藍色,運行效果如圖5所示。

圖5 自定義大頭針

5 啟動地圖APP

上一節點擊信息按鈕,并沒有反應,接下來就要加入點擊信息按鈕的事件響應,這里我們是跳轉到地圖app中,顯示從當前位置到公園的駕駛路線。

首先需要在類Artwork中加入一個方法,用來創建MapItem。這里需要導入Contacts頭文件(原文中用的是Address頭文件,iOS9以后的系統中已經不用Address,所以我這里用Contacts來替代)。

#import <Contacts/Contacts.h>
- (MKMapItem *)mapItem {
    NSDictionary *addressDictionary = @{CNPostalAddressStreetKey: self.locationName};
    MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate:self.coordinate addressDictionary:addressDictionary];
    MKMapItem *mapItem = [[MKMapItem alloc] initWithPlacemark:placemark];
    return mapItem;
}

然后在ViewController中實現另外一個協議方法如下。另外,在Xcode菜單欄的Product\Scheme\Edit Scheme選擇Run的Options選項,設置好默認位置為Honolulu,如圖6所示。這樣點擊右側的信息按鈕,就會跳轉到地圖APP中了(這里可能是由于高德地圖問題,顯示不了駕駛路線,暫時沒有找到解決方法,若有知道的,麻煩告知一聲)。

圖6 默認位置設置
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
    Artwork *artwork = (Artwork *)view.annotation;
    NSDictionary *launchOptions = @{MKLaunchOptionsDirectionsModeKey:MKLaunchOptionsDirectionsModeDriving};
    [[artwork mapItem] openInMapsWithLaunchOptions:launchOptions];
}

運行效果如下:

圖7 跳轉到地圖APP

6 用戶位置授權

在iOS應用中,如果應用要請求位置信息,一般是需要提示用戶是否授權的,這個功能怎么實現呢?首先在ViewController中加入CLLocationManager,然后在viewDidAppear中加入請求授權的函數調用,如果一次請求授權允許了,系統會記錄授權的狀態,下次啟動應用就不需要再次授權了。如果拒絕授權了,以后要開啟只能到系統設置里面開啟。

注意:一般請求授權分為兩種方式,一種是requestWhenInUseAuthorization表示只有應用在前臺允許的時候獲取位置信息,而另外一種是requestAlwaysAuthorization表示只要應用在運行就可以獲取位置信息,不管在前臺還是后臺運行,為了不泄露隱私,蘋果官方是建議用第一種,即在前臺運行的時候運行訪問位置信息。

另外一個容易忽視的一點,就是還需要在項目的Info.plist中加入一個配置。配置鍵名為NSLocationWhenInUseUsageDescription,內容為請求授權的文字信息,本項目填的信息為To show you cool things nearby

@property (strong, nonatomic) CLLocationManager *locationManager;

- (void)checkLocationStatus {
    if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedWhenInUse) {
        self.mapView.showsUserLocation = YES;
    } else {
        [self.locationManager requestWhenInUseAuthorization];
    }
}

這樣在啟動應用的時候,就會彈出一個提示框,內容為應用請求訪問您的位置信息,讓你決定是否授權。效果如圖8所示:

圖8 請求授權效果圖

7 其他

原文中還有一節是通過一個JSON文件來設置多個大頭針,并根據位置信息不同設置不同的大頭針的顏色,與設置一個大頭針效果類似,只是多了JSON解析的步驟,這里不再贅述,可以參見我的項目最終代碼。

另外,地圖里面還可以設置覆蓋層(overlay),比如用圖片來設置覆蓋層,或者設置路徑,多邊形等,可以參見這篇文章,這篇文章代碼的Objective-C版本地址參見這里

8 完整代碼

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,791評論 6 545
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,795評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,943評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,057評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,773評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,106評論 1 330
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,082評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,282評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,793評論 1 338
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,507評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,741評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,220評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,929評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,325評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,661評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,482評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,702評論 2 380

推薦閱讀更多精彩內容