要想讓MapView畫路徑,必然要傳給mapView某些東西,沒錯,相似Annotation(大頭針),添加路徑也有相似的操做函數和相應傳入CLLocation返回路徑的協議方法。數組
1.搭建界面函數
拖一個全屏的MapView,連線到controller,以下ui
1 @property (weak, nonatomic) IBOutlet MKMapView *mapView;
2. 建立一個編碼器(地理編碼,不要誤解)編碼
1 @property (nonatomic, strong) CLGeocoder *geocoder;
並讓它成爲懶加載對象:atom
1 - (CLGeocoder *)geocoder 2 { 3 if (!_geocoder) { 4 self.geocoder = [[CLGeocoder alloc] init]; 5 } 6 return _geocoder; 7 }
上面這些不走都是無腦完成的,寫的多了都輕車熟路。下面纔是重頭戲。spa
3. 開始以前先拿到起始點和終點的地理信息再說代理
(1) 在這以前咱們是否是要設置mapView的代理呢code
遵照協議對象
1 @interface ViewController () <MKMapViewDelegate>
設置代理:blog
1 self.mapView.delegate = self;
(2) 開始幹活
1 NSString *address1 = @"北京"; 2 NSString *address2 = @"上海"; 3 4 [self.geocoder geocodeAddressString:address1 completionHandler:^(NSArray *placemarks, NSError *error) { 5 if (error) return; 6 7 CLPlacemark *fromPm = [placemarks firstObject]; 8 9 [self.geocoder geocodeAddressString:address2 completionHandler:^(NSArray *placemarks, NSError *error) { 10 if (error) return; 11 12 CLPlacemark *toPm = [placemarks firstObject]; 13 14 [self addLineFrom:fromPm to:toPm]; 15 }]; 16 }];
有心的同志可能觀察到:怎麼兩個反地理編碼是嵌套的。吶,這裏是你要注意的,在一個controller中只能同時存在一個地理編碼信息。若是反編碼完起始點就跳出block,那麼當反編碼完第二個的時候,第一個就被銷燬了。而嵌套block則不會。這裏你能夠理解爲block裏面的信息還不歸屬controller管理。
咱們反地理編碼獲得的老是一系列的符合結果的地理信息數組,可是隻有最好的那個纔是咱們須要的,因此老是取出數組中的第一個object。地理信息的類型是CLPlacemark類型,這個類型在添加大頭針的時候確定不會陌生。它就是封裝了地理座標CLLocationCoordinate的一個類型。
咱們經過反地理編碼的獲得了兩個地理信息,那接下來就開始劃線吧。方法
addLineFrom:fromPm to:toPm
是咱們本身建立的,這樣防止一個方法裏面放置太多的代碼,也實現代碼的聚合性(一段代碼只實現一個功能)。
4. 實現addLineFrom:(CLPlacemark *)from to:(CLPlacemark *)to
(1) 雖然咱們設置了開始和結束,可是咱們並無告訴mapView究竟是從"北京"到"上海",仍是"上海"到"北京",咱們如今設置的信息都只是咱們單方面的一廂情願的。
1 // 方向請求 2 MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init]; 3 // 設置起點 4 MKPlacemark *sourcePm = [[MKPlacemark alloc] initWithPlacemark:fromPm]; 5 request.source = [[MKMapItem alloc] initWithPlacemark:sourcePm]; 6 7 // 設置終點 8 MKPlacemark *destinationPm = [[MKPlacemark alloc] initWithPlacemark:toPm]; 9 request.destination = [[MKMapItem alloc] initWithPlacemark:destinationPm];
傳進來的CLPlacemark對象又一次被封裝到MKPlacemark中了。這是能夠理解的,畢竟MapView和CLLocation仍是有一點區別的。
這還沒完,到這裏咱們只是設置了請求(request),尚未請求,下面咱們請求設置方向
1 // 方向對象 2 MKDirections *directions = [[MKDirections alloc] initWithRequest:request];
方向,和兩個地點都有了,至少咱們認爲不缺乏什麼東西了,告訴你方向,從哪裏出發,到那裏出發,你還不知道怎麼走,那你就去死吧。或許你擔憂可能如今的數據還要進一步封裝,可是你並不知道怎麼封裝,那麼我告訴你,到這裏已經不須要封裝了,咱們獲得了mapView能識別的數據類型。
(2) 那下面咱們開始添加咯
前面咱們說過,相似添加大頭針的addAnnotation:,這裏有一個addOverlay:,只要咱們點用這個就能添加路線了。可是添加了顯示仍是一回事(就向添加普通view時沒有設置frame同樣,添加了可是沒有顯示。可是這裏缺不是frame的問題,後面會介紹的)。
從咱們如今的信息得到路線,調用addOverlay:
1 [directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) { 2 // NSLog(@"總共%lu條路線", [response.routes count]); 3 4 // code 5 6 }];
咱們調用了MKDirections的方法,你問我爲何是這個?這他媽就是這麼用的哪有那麼多爲何。
這個方法會幫你計算路線,完事以後還會回調一個block,而獲得的路線和其餘信息都封裝在response中讓你操做,同事還煩會給你了錯誤信息。
那咱們就不客氣了,解析出路線(路線在iOS中是MKRoute對象)
1 for (MKRoute *route in response.routes) { 2 // 添加路線遮蓋 3 [self.mapView addOverlay:route.polyline]; 4 }
奧,這裏叫路線遮蓋,可能你從addOverlay就開始疑問了,爲何不是addRoute?能夠這麼理解,你添加的路線是蓋在mapView上面的,而不是mapView自帶的屬性。
ok,咱們暴力添加了全部獲得的路線遮蓋,可是運行一下你就知道,並無顯示路線,爲何呢,咱們的邏輯到如今都都沒有錯,難道是哪裏錯了我不知道?實際上是沒有錯的,是還沒完成。
(3) 實現代理方法
須要實現代理方法才能顯示。
還記得添加大頭針的時候須要實現一個代理方法返回大頭針view嗎,這裏也是
1 #pragma mark - MKMapViewDelegate 2 - (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay 3 { 4 MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithOverlay:overlay]; 5 renderer.strokeColor = [UIColor redColor]; 6 return renderer; 7 }
就是這個逼,每次調用addOverlay時,都會調用一次這個代理方法。
這個方法傳入MapView和錄像遮蓋overlay,返回MKOverlayRender類型,而MKOverlayRender是第一次出現,是什麼鬼?看來得建立MKOverlayRender這個對象並返回他了。
代碼中你就看出了,咱們並無用MKOverlayRender這個類型,而是用了MKPolylineRender(MKOverlayRender的子類)。由於MKOverlayRender連個屬性都沒有。試想一下你添加的路徑沒有線寬和顏色,那你他媽看得見嗎。因此咱們使用MKPolylineRender子類。他有一系列的屬性(按住command,左鍵點擊MKPolylineRender便可查看)能夠設置,根據喜愛本身發揮吧。
運行你就發現所言非虛了。
5. 添加大頭針
這裏純屬拓展
在- (void)addLineFrom:(CLPlacemark *)fromPm to:(CLPlacemark *)toPm方法實現開始時添加代碼
1 // 1.添加2個大頭針 2 LSAnnotation *fromAnno = [[LsAnnotation alloc] init]; 3 fromAnno.coordinate = fromPm.location.coordinate; 4 fromAnno.title = fromPm.name; 5 [self.mapView addAnnotation:fromAnno]; 6 7 LsAnnotation *toAnno = [[LsAnnotation alloc] init]; 8 toAnno.coordinate = toPm.location.coordinate; 9 toAnno.title = toPm.name; 10 [self.mapView addAnnotation:toAnno];
這裏就是純添加兩個大頭針,利用傳進來的兩個地點信息。LsAnnotation時本身建立的實現了<MKAnnotation>協議的大頭針,並添加了幾個屬性,添加出來的就是一個紅色的大頭針,你想要其餘樣式請移步到其餘教程。
這裏給出.h文件,.m文件沒有任何實現,因此不給了
1 #import <Foundation/Foundation.h> 2 #import <MapKit/MapKit.h> 3 @interface LsAnnotation : NSObject <MKAnnotation> 4 @property (nonatomic) CLLocationCoordinate2D coordinate;//required 5 @property (nonatomic, copy) NSString *title; 6 @property (nonatomic, copy) NSString *subtitle; 7 8 @end
ok,結束了。
給出controller的完整代碼
1 // 2 // LsViewController.m 3 // 07-導航畫線 4 // 5 // 6 7 #import "LsViewController.h" 8 #import "LsAnnotation.h" 9 #import <MapKit/MapKit.h> 10 #import <CoreLocation/CoreLocation.h> 11 12 @interface MJViewController () <MKMapViewDelegate> 13 @property (weak, nonatomic) IBOutlet MKMapView *mapView; 14 @property (nonatomic, strong) CLGeocoder *geocoder; 15 @end 16 17 @implementation MJViewController 18 19 - (CLGeocoder *)geocoder 20 { 21 if (!_geocoder) { 22 self.geocoder = [[CLGeocoder alloc] init]; 23 } 24 return _geocoder; 25 } 26 27 - (void)viewDidLoad 28 { 29 [super viewDidLoad]; 30 31 self.mapView.delegate = self; 32 33 NSString *address1 = @"北京"; 34 NSString *address2 = @"廣州"; 35 36 [self.geocoder geocodeAddressString:address1 completionHandler:^(NSArray *placemarks, NSError *error) { 37 if (error) return; 38 39 CLPlacemark *fromPm = [placemarks firstObject]; 40 41 [self.geocoder geocodeAddressString:address2 completionHandler:^(NSArray *placemarks, NSError *error) { 42 if (error) return; 43 44 CLPlacemark *toPm = [placemarks firstObject]; 45 46 [self addLineFrom:fromPm to:toPm]; 47 }]; 48 }]; 49 50 51 } 52 53 /** 54 * 添加導航的線路 55 * 56 * @param fromPm 起始位置 57 * @param toPm 結束位置 58 */ 59 - (void)addLineFrom:(CLPlacemark *)fromPm to:(CLPlacemark *)toPm 60 { 61 // 1.添加2個大頭針 62 LsAnnotation *fromAnno = [[LsAnnotation alloc] init]; 63 fromAnno.coordinate = fromPm.location.coordinate; 64 fromAnno.title = fromPm.name; 65 [self.mapView addAnnotation:fromAnno]; 66 67 LsAnnotation *toAnno = [[LsAnnotation alloc] init]; 68 toAnno.coordinate = toPm.location.coordinate; 69 toAnno.title = toPm.name; 70 [self.mapView addAnnotation:toAnno]; 71 72 // 2.查找路線 73 74 // 方向請求 75 MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init]; 76 // 設置起點 77 MKPlacemark *sourcePm = [[MKPlacemark alloc] initWithPlacemark:fromPm]; 78 request.source = [[MKMapItem alloc] initWithPlacemark:sourcePm]; 79 80 // 設置終點 81 MKPlacemark *destinationPm = [[MKPlacemark alloc] initWithPlacemark:toPm]; 82 request.destination = [[MKMapItem alloc] initWithPlacemark:destinationPm]; 83 84 // 方向對象 85 MKDirections *directions = [[MKDirections alloc] initWithRequest:request]; 86 87 // 計算路線 88 [directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) { 89 // NSLog(@"總共%lu條路線", [response.routes count]); 90 91 // 遍歷全部的路線 92 for (MKRoute *route in response.routes) { 93 // 添加路線遮蓋 94 [self.mapView addOverlay:route.polyline]; 95 } 96 }]; 97 } 98 99 #pragma mark - MKMapViewDelegate 100 - (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay 101 { 102 MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithOverlay:overlay]; 103 renderer.strokeColor = [UIColor redColor]; 104 return renderer; 105 } 106 @end