iOS-原生地圖開發進階——使用導航和附近興趣點檢索

weixin_33860722發表於2016-08-26

iOS中的mapKit框架對國際化的支援非常出色。在前些篇部落格中,對這個地圖框架的基礎用法和標註與覆蓋物的新增進行了詳細的介紹,這篇部落格將介紹兩個更加實用的功能的開發:線路導航與興趣點搜尋。前幾篇部落格的連結如下:
地圖基礎用法詳解:http://my.oschina.net/u/2340880/blog/415360

新增大頭針與自定義標註:http://my.oschina.net/u/2340880/blog/415441

新增地圖覆蓋物:http://my.oschina.net/u/2340880/blog/415611

一、線路導航

1、從幾個類的關係說起

(1)MKPlacemark

一個地點資訊類,如下:

@interface MKPlacemark : CLPlacemark <MKAnnotation>
//初始化方法,通過給定一個經緯度和地點資訊字典
- (instancetype)initWithCoordinate:(CLLocationCoordinate2D)coordinate
                 addressDictionary:(NSDictionary *)addressDictionary;
//國家編碼
@property (nonatomic, readonly) NSString *countryCode;
@end

(2)MKMapItem

地點節點類,包含此節點的許多地點資訊,如下:

@interface MKMapItem : NSObject
//當前節點的地點資訊物件
@property (nonatomic, readonly) MKPlacemark *placemark;
//是否是當前位置
@property (nonatomic, readonly) BOOL isCurrentLocation;
//節點名稱
@property (nonatomic, copy) NSString *name;
//電話號碼
@property (nonatomic, copy) NSString *phoneNumber;
//網址
@property (nonatomic, strong) NSURL *url;
//將當前位置建立為節點
+ (MKMapItem *)mapItemForCurrentLocation;
//由一個位置資訊建立節點
- (instancetype)initWithPlacemark:(MKPlacemark *)placemark;
 
@end

(3)MKDirectionsRequest

導航請求類

@interface MKDirectionsRequest : NSObject
//起點節點
- (MKMapItem *)source NS_AVAILABLE(10_9, 6_0);
- (void)setSource:(MKMapItem *)source NS_AVAILABLE(10_9, 7_0);
//目的地節點
- (MKMapItem *)destination NS_AVAILABLE(10_9, 6_0);
- (void)setDestination:(MKMapItem *)destination NS_AVAILABLE(10_9, 7_0);
 
@end

這個類還有一些擴充套件的設定屬性:

@property (nonatomic) MKDirectionsTransportType transportType;

設定路線檢索型別,列舉如下:

typedef NS_OPTIONS(NSUInteger, MKDirectionsTransportType) {
    MKDirectionsTransportTypeAutomobile     = 1 << 0,//適合駕車時導航
    MKDirectionsTransportTypeWalking        = 1 << 1,//適合步行時導航
    MKDirectionsTransportTypeAny            = 0x0FFFFFFF//任何情況
};
@property (nonatomic) BOOL requestsAlternateRoutes;

設定是否搜尋多條線路

@property (nonatomic, copy) NSDate *departureDate;

設定出發日期

@property (nonatomic, copy) NSDate *arrivalDate;

設定到達日期

(4)MKDirections

從apple伺服器獲取資料的連線類

@interface MKDirections : NSObject
//初始化方法
- (instancetype)initWithRequest:(MKDirectionsRequest *)request NS_DESIGNATED_INITIALIZER;
//開始計算線路資訊
- (void)calculateDirectionsWithCompletionHandler:(MKDirectionsHandler)completionHandler;
//開始計算時間資訊
- (void)calculateETAWithCompletionHandler:(MKETAHandler)completionHandler;
//取消
- (void)cancel;
//是否正在計算
@property (nonatomic, readonly, getter=isCalculating) BOOL calculating;
@end

(5)MKDirectionsResponse

線路資訊結果類

@interface MKDirectionsResponse : NSObject
@property (nonatomic, readonly) MKMapItem *source;//起點
@property (nonatomic, readonly) MKMapItem *destination;//終點
@property (nonatomic, readonly) NSArray *routes; //線路規劃陣列
@end

(6)MKETResponse

時間資訊結果類

@interface MKETAResponse : NSObject
@property (nonatomic, readonly) MKMapItem *source;//起點
@property (nonatomic, readonly) MKMapItem *destination;//終點
@property (nonatomic, readonly) NSTimeInterval expectedTravelTime;//耗時
 
@end

(7)MKRoute

線路資訊類,導航的線路結果是這個型別的物件

@interface MKRoute : NSObject
 
@property (nonatomic, readonly) NSString *name; //線路名稱
@property (nonatomic, readonly) NSArray *advisoryNotices; //注意事項
@property (nonatomic, readonly) CLLocationDistance distance; //距離
@property (nonatomic, readonly) NSTimeInterval expectedTravelTime;//耗時
@property (nonatomic, readonly) MKDirectionsTransportType transportType; //檢索的型別
 
@property (nonatomic, readonly) MKPolyline *polyline; // 線路覆蓋物
 
@property (nonatomic, readonly) NSArray *steps; // 線路詳情陣列
 
@end

(8)MKRouteStep

線路詳情資訊類,線路中每一步的資訊都是這個類的物件

@interface MKRouteStep : NSObject
 
@property (nonatomic, readonly) NSString *instructions; // 節點資訊
@property (nonatomic, readonly) NSString *notice; // 注意事項
 
@property (nonatomic, readonly) MKPolyline *polyline; //線路覆蓋物
 
@property (nonatomic, readonly) CLLocationDistance distance; // 距離
 
@property (nonatomic, readonly) MKDirectionsTransportType transportType; // 導航型別
 
@end

看到上面如此多的類,你可能會覺得一頭霧水,那麼不用著急,類雖然繁雜,但他們之間的邏輯非常清晰,下面就通過一個例子來進行線路導航。

2、進行線路導航

- (void)viewDidLoad {
    [super viewDidLoad];
    //地圖初始化設定
    mapView =[[MKMapView alloc]initWithFrame:self.view.frame];
    mapView.region=MKCoordinateRegionMake(CLLocationCoordinate2DMake(39.26, 116.3), MKCoordinateSpanMake(5, 5));
    mapView.mapType=MKMapTypeStandard;
    mapView.delegate=self;
    [self.view addSubview:mapView];
     
    //導航設定
    CLLocationCoordinate2D fromcoor=CLLocationCoordinate2DMake(39.26, 116.3);
    CLLocationCoordinate2D tocoor = CLLocationCoordinate2DMake(33.33, 113.33);
    //建立出發點和目的點資訊
    MKPlacemark *fromPlace = [[MKPlacemark alloc] initWithCoordinate:fromcoor
                                                       addressDictionary:nil];
    MKPlacemark *toPlace = [[MKPlacemark alloc]initWithCoordinate:tocoor addressDictionary:nil];
    //建立出發節點和目的地節點
    MKMapItem * fromItem = [[MKMapItem alloc]initWithPlacemark:fromPlace];
    MKMapItem * toItem = [[MKMapItem alloc]initWithPlacemark:toPlace];
    //初始化導航搜尋請求
    MKDirectionsRequest *request = [[MKDirectionsRequest alloc]init];
    request.source=fromItem;
    request.destination=toItem;
    request.requestsAlternateRoutes=YES;
    //初始化請求檢索
    MKDirections *directions = [[MKDirections alloc]initWithRequest:request];
    //開始檢索,結果會返回在block中
    [directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) {
        if (error) {
            NSLog(@"error:%@",error);
        }else{
            //提取導航線路結果中的一條線路
            MKRoute *route =response.routes[0];
            //將線路中的每一步詳情提取出來
            NSArray * stepArray = [NSArray arrayWithArray:route.steps];
            //進行遍歷
            for (int i=0; i<stepArray.count; i++) {
                //線路的詳情節點
                MKRouteStep * step = stepArray[i];
                //在此節點處新增一個大頭針
                MKPointAnnotation * point = [[MKPointAnnotation alloc]init];
                point.coordinate=step.polyline.coordinate;
                point.title=step.instructions;
                point.subtitle=step.notice;
                [mapView addAnnotation:point];
                //將此段線路新增到地圖上
                [mapView addOverlay:step.polyline];
            }
        }
    }];  
}
//地圖覆蓋物的代理方法
-(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay{
    MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithPolyline:overlay];
     
    renderer.strokeColor = [UIColor redColor];
     
    renderer.lineWidth = 4.0;
     
    return  renderer;
}
//標註的代理方法
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
    MKPinAnnotationView * view= [[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:@"anno"];
    view.canShowCallout=YES;
    return view;
}

效果如下:

1354012-ee14f2d1af7b979a.png
Paste_Image.png

二、附近興趣點檢索

興趣點檢索的邏輯和導航線路檢索的邏輯相似,直接通過程式碼來演示:

    //建立一個位置資訊物件,第一個引數為經緯度,第二個為緯度檢索範圍,單位為米,第三個為經度檢索範圍,單位為米
    MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(tocoor, 5000, 5000);
    //初始化一個檢索請求物件
    MKLocalSearchRequest * req = [[MKLocalSearchRequest alloc]init];
    //設定檢索引數
    req.region=region;
    //興趣點關鍵字
    req.naturalLanguageQuery=@"hotal";
    //初始化檢索
    MKLocalSearch * ser = [[MKLocalSearch alloc]initWithRequest:req];
    //開始檢索,結果返回在block中
    [ser startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) {
        //興趣點節點陣列
        NSArray * array = [NSArray arrayWithArray:response.mapItems];
        for (int i=0; i<array.count; i++) {
            MKMapItem * item=array[i];
            MKPointAnnotation * point = [[MKPointAnnotation alloc]init];
            point.title=item.name;
            point.subtitle=item.phoneNumber;
            point.coordinate=item.placemark.coordinate;
            [mapView addAnnotation:point];
        }
    }];

效果如下:

1354012-5578133439eea7a0.png
Paste_Image.png

相關文章