iOS學(xué)習(xí)筆記(9)-地圖MapKit入門

這篇文章還是翻譯自raywenderlich宋下,用Objective-C改寫了代碼。沒有逐字翻譯渡蜻,如有錯(cuò)漏术吝,請(qǐng)指出。原文地址在這里茸苇。

1 概述

MapKit是iOS提供的一個(gè)很便捷的API排苍,旨在幫助我們快速開發(fā)地理位置相關(guān)的應(yīng)用。在這篇博客中涉及的地方叫Honolulu学密,是美國(guó)的一個(gè)城市淘衙,中文名是檀香山,是美國(guó)夏威夷州首府和港口城市腻暮。我第一次聽說檀香山應(yīng)該是在歷史書上彤守,似乎跟孫中山先生相關(guān)毯侦,這里暫時(shí)按下不表。

本文的例子中我們要添加一個(gè)地圖到APP中具垫,然后通過經(jīng)緯度定位到一個(gè)指定的位置侈离,通過大頭針的形式來展示定位,點(diǎn)擊大頭針會(huì)顯示位置的一些信息做修。我們可以設(shè)置大頭針的顏色霍狰,當(dāng)然我們更可以自定義圖片來替換默認(rèn)的大頭針抡草,豐富地圖內(nèi)容饰及。

2 開始

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

圖1 添加 Map Kit View

然后需要在ViewController.m中添加Map View的outlet關(guān)聯(lián),通過CTRL+DRAG即可橘忱,命名為mapView赴魁,代碼如下,別忘記引入MapKit頭文件钝诚,注意要先導(dǎo)入MapKit庫(Xcode7.3里面颖御,先選擇工程,然后在Capabilities那一項(xiàng)把Maps開關(guān)打開):

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

這樣凝颇,我們編譯運(yùn)行項(xiàng)目潘拱,可以看到地圖出現(xiàn)了,默認(rèn)顯示的是中國(guó)地圖在中央位置拧略,這個(gè)應(yīng)該是跟系統(tǒng)環(huán)境相關(guān)芦岂。如圖2所示:

圖2 地圖視圖

3 設(shè)置可視區(qū)域

接下來重點(diǎn)來了,我們要設(shè)置一個(gè)可視區(qū)域垫蛆。學(xué)過地理
的都知道(我是地理盲)禽最,一個(gè)地理位置我們是通過緯度和經(jīng)度來確定一個(gè)位置,緯度中北緯和南緯各分為90度袱饭,經(jīng)度西經(jīng)和東經(jīng)則各為180度弛随。在iOS開發(fā)中,北緯和東經(jīng)我們用正數(shù)表示宁赤,南緯和西經(jīng)用負(fù)數(shù)表示舀透。

接下來我們要設(shè)置一個(gè)可視區(qū)域,不設(shè)置我們看到的只是一個(gè)默認(rèn)區(qū)域决左,如前面看到的一樣愕够。設(shè)置可視區(qū)域的代碼如下走贪,然后在方法viewDidLoad中加入調(diào)用:

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

這里來解析一下,首先是設(shè)置好中心點(diǎn)的經(jīng)緯度惑芭。然后是設(shè)置區(qū)域半徑坠狡,包括橫向和縱向半徑,這里都設(shè)置的為2000米(南北和東西的跨度范圍)遂跟。接著根據(jù)中心點(diǎn)經(jīng)緯度和區(qū)域半徑創(chuàng)建一個(gè)Region逃沿,最后調(diào)用MapView的setRegion方法即可。這時(shí)我們?cè)龠\(yùn)行代碼可以看到效果如圖3所示幻锁,我們看到與前面不同了凯亮,確實(shí)地圖已經(jīng)定位到我們?cè)O(shè)置的中心點(diǎn)和區(qū)域大小了:

圖3 設(shè)置可視區(qū)域

4 設(shè)置標(biāo)記

接下來來設(shè)置一個(gè)標(biāo)記,也就是通常見到的那種大頭針哄尔。先新建一個(gè)類Artwork來表示標(biāo)記內(nèi)容假消,包括位置坐標(biāo),標(biāo)題和副標(biāo)題等岭接。位置坐標(biāo)用于確定大頭針位置富拗,而標(biāo)題和副標(biāo)題則是點(diǎn)擊大頭針的時(shí)候顯示的內(nèi)容。

@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];
}

注意這里的坐標(biāo)暫時(shí)是自己手動(dòng)指定啃沪,在后面我們會(huì)從一個(gè)JSON文件中解析一系列的坐標(biāo)位置然后設(shè)置多個(gè)大頭針。然后里面的locationName其實(shí)是位置名字窄锅,而MKAnnotation是一個(gè)協(xié)議创千,地圖標(biāo)記的協(xié)議,它里面主要定義了一系列的屬性值(這里可以發(fā)現(xiàn)協(xié)議不只有方法酬滤,也可以定義屬性的)签餐,就是標(biāo)記必須的幾個(gè)屬性title,subtitle盯串,coordinate氯檐。
然后在viewDidLoad中加入該方法的調(diào)用,可以看到大頭針顯示体捏,點(diǎn)擊可以看到title和subtitle的顯示冠摄。

圖4 大頭針展示

僅僅這樣當(dāng)然是不夠的,為了APP的個(gè)性化几缭,我們希望可以自定義大頭針顯示方式河泳,可以通過設(shè)置ViewController實(shí)現(xiàn)協(xié)議MKMapViewDelegate,然后將mapView的delegate設(shè)置為ViewController年栓,并在ViewController中實(shí)現(xiàn)協(xié)議的viewForAnnotation方法即可拆挥。代碼如下:

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

//2 新增代理方法實(shí)現(xiàn)
#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];
             //自定義后需要設(shè)置canShowCallout為YES,不然點(diǎn)擊不會(huì)顯示信息某抓。
            view.canShowCallout = YES;
            //設(shè)置信息展示偏移
            view.calloutOffset = CGPointMake(-10, 5);
            //設(shè)置信息按鈕
            view.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
        }
        //設(shè)置大頭針顏色
        view.pinTintColor = [UIColor blueColor];      
        return view;
    }
    return nil;
}

方法viewForAnnotation中我們定義了大頭針的信息偏移和在顯示內(nèi)容中添加了一個(gè)信息按鈕纸兔。偏移位置是針對(duì)大頭針的中間頂部而言的惰瓜,這里我們?cè)O(shè)置信息展示的X軸向左偏移中間位置10個(gè)Point,Y軸則從頂部往下移動(dòng)5個(gè)Point汉矿,并將大頭針的顏色設(shè)置為藍(lán)色崎坊,運(yùn)行效果如圖5所示。

圖5 自定義大頭針

5 啟動(dòng)地圖APP

上一節(jié)點(diǎn)擊信息按鈕洲拇,并沒有反應(yīng)奈揍,接下來就要加入點(diǎn)擊信息按鈕的事件響應(yīng)爆哑,這里我們是跳轉(zhuǎn)到地圖app中今野,顯示從當(dāng)前位置到公園的駕駛路線。

首先需要在類Artwork中加入一個(gè)方法湿硝,用來創(chuàng)建MapItem蚕捉。這里需要導(dǎo)入Contacts頭文件(原文中用的是Address頭文件奏篙,iOS9以后的系統(tǒng)中已經(jīng)不用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中實(shí)現(xiàn)另外一個(gè)協(xié)議方法如下。另外为严,在Xcode菜單欄的Product\Scheme\Edit Scheme選擇Run的Options選項(xiàng)敛熬,設(shè)置好默認(rèn)位置為Honolulu,如圖6所示第股。這樣點(diǎn)擊右側(cè)的信息按鈕应民,就會(huì)跳轉(zhuǎn)到地圖APP中了(這里可能是由于高德地圖問題,顯示不了駕駛路線夕吻,暫時(shí)沒有找到解決方法诲锹,若有知道的,麻煩告知一聲)涉馅。

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

運(yùn)行效果如下:

圖7 跳轉(zhuǎn)到地圖APP

6 用戶位置授權(quán)

在iOS應(yīng)用中归园,如果應(yīng)用要請(qǐng)求位置信息,一般是需要提示用戶是否授權(quán)的稚矿,這個(gè)功能怎么實(shí)現(xiàn)呢庸诱?首先在ViewController中加入CLLocationManager,然后在viewDidAppear中加入請(qǐng)求授權(quán)的函數(shù)調(diào)用晤揣,如果一次請(qǐng)求授權(quán)允許了桥爽,系統(tǒng)會(huì)記錄授權(quán)的狀態(tài),下次啟動(dòng)應(yīng)用就不需要再次授權(quán)了昧识。如果拒絕授權(quán)了钠四,以后要開啟只能到系統(tǒng)設(shè)置里面開啟。

注意:一般請(qǐng)求授權(quán)分為兩種方式跪楞,一種是requestWhenInUseAuthorization表示只有應(yīng)用在前臺(tái)允許的時(shí)候獲取位置信息缀去,而另外一種是requestAlwaysAuthorization表示只要應(yīng)用在運(yùn)行就可以獲取位置信息环疼,不管在前臺(tái)還是后臺(tái)運(yùn)行,為了不泄露隱私朵耕,蘋果官方是建議用第一種炫隶,即在前臺(tái)運(yùn)行的時(shí)候運(yùn)行訪問位置信息。

另外一個(gè)容易忽視的一點(diǎn)阎曹,就是還需要在項(xiàng)目的Info.plist中加入一個(gè)配置伪阶。配置鍵名為NSLocationWhenInUseUsageDescription,內(nèi)容為請(qǐng)求授權(quán)的文字信息处嫌,本項(xiàng)目填的信息為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];
    }
}

這樣在啟動(dòng)應(yīng)用的時(shí)候,就會(huì)彈出一個(gè)提示框熏迹,內(nèi)容為應(yīng)用請(qǐng)求訪問您的位置信息檐薯,讓你決定是否授權(quán)。效果如圖8所示:

圖8 請(qǐng)求授權(quán)效果圖

7 其他

原文中還有一節(jié)是通過一個(gè)JSON文件來設(shè)置多個(gè)大頭針注暗,并根據(jù)位置信息不同設(shè)置不同的大頭針的顏色坛缕,與設(shè)置一個(gè)大頭針效果類似,只是多了JSON解析的步驟捆昏,這里不再贅述赚楚,可以參見我的項(xiàng)目最終代碼。

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

8 完整代碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末遍烦,一起剝皮案震驚了整個(gè)濱河市俭嘁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌乳愉,老刑警劉巖兄淫,帶你破解...
    沈念sama閱讀 222,590評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異蔓姚,居然都是意外死亡捕虽,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門坡脐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來泄私,“玉大人,你說我怎么就攤上這事∩味耍” “怎么了捅暴?”我有些...
    開封第一講書人閱讀 169,301評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)咧纠。 經(jīng)常有香客問我蓬痒,道長(zhǎng),這世上最難降的妖魔是什么漆羔? 我笑而不...
    開封第一講書人閱讀 60,078評(píng)論 1 300
  • 正文 為了忘掉前任梧奢,我火速辦了婚禮,結(jié)果婚禮上演痒,老公的妹妹穿的比我還像新娘亲轨。我一直安慰自己,他們只是感情好鸟顺,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評(píng)論 6 398
  • 文/花漫 我一把揭開白布惦蚊。 她就那樣靜靜地躺著,像睡著了一般讯嫂。 火紅的嫁衣襯著肌膚如雪蹦锋。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,682評(píng)論 1 312
  • 那天端姚,我揣著相機(jī)與錄音晕粪,去河邊找鬼挤悉。 笑死渐裸,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的装悲。 我是一名探鬼主播昏鹃,決...
    沈念sama閱讀 41,155評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼诀诊!你這毒婦竟也來了洞渤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,098評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤属瓣,失蹤者是張志新(化名)和其女友劉穎载迄,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抡蛙,經(jīng)...
    沈念sama閱讀 46,638評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡护昧,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了粗截。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片惋耙。...
    茶點(diǎn)故事閱讀 40,852評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出绽榛,到底是詐尸還是另有隱情湿酸,我是刑警寧澤,帶...
    沈念sama閱讀 36,520評(píng)論 5 351
  • 正文 年R本政府宣布灭美,位于F島的核電站推溃,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏届腐。R本人自食惡果不足惜美莫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望梯捕。 院中可真熱鬧厢呵,春花似錦、人聲如沸傀顾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽短曾。三九已至寒砖,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間嫉拐,已是汗流浹背哩都。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留婉徘,地道東北人漠嵌。 一個(gè)月前我還...
    沈念sama閱讀 49,279評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像盖呼,于是被迫代替她去往敵國(guó)和親儒鹿。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容