在MapView中添加路徑

要想讓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

 

相關文章
相關標籤/搜索