百度地圖檢索以及路徑規劃
代碼地址如下:<br>http://www.demodashi.com/demo/11030.html
一、準備工作
- 需要集成百度地圖SDK
- 需要申請百度地圖AppKey
- 本例子實現了POI檢索以及詳情檢索、路線規劃
二、程序實現
首先貼一下項目截圖:
(項目截圖1)
(項目截圖2)
POI詳情:
第一步:在Appdelegate.m
中設置AppKey
。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; HouseMapTootsViewController *vc = [[HouseMapTootsViewController alloc] init]; vc.latitude = 31.976; vc.longitude = 118.71; UINavigationController *navi = [[UINavigationController alloc] initWithRootViewController:vc]; //配置百度地圖 [self configurationBMKMap]; self.window.rootViewController = navi; [self.window makeKeyAndVisible]; return YES; } #pragma mark -- 百度地圖 - (void)configurationBMKMap { // 要使用百度地圖,請先啟動BaiduMapManager _mapManager = [[BMKMapManager alloc] init]; BOOL ret = [_mapManager start:@"appkey" generalDelegate:self]; if (!ret) { NSLog(@"manager start failed!"); } }
第二步:完成代理
#pragma mark -- BMKGeneralDelegate - (void)onGetNetworkState:(int)iError { if (0 == iError) { NSLog(@"聯網成功"); }else { NSLog(@"onGetNetworkState %d",iError); } } - (void)onGetPermissionState:(int)iError { if (0 == iError) { NSLog(@"授權成功"); }else { NSLog(@"onGetPermissionState %d",iError); } }
第三步:創建百度地圖,開啟用戶定位(後面路線規劃需要)。並且添加一個大頭針,這個大頭針就是你即將檢索的中心點。
self.mapView = [[BMKMapView alloc] initWithFrame:CGRectMake(0, 40+64, kScreenWidth, kScreenHeight - 40 - 64)]; [self.view addSubview:self.mapView]; [self.view addSubview:self.planView]; self.locService = [[BMKLocationService alloc] init]; self.mapView.delegate = self; self.locService.delegate = self; //定位方向模式 不能使用跟隨,不然地圖中心就不是大頭針了 [self.mapView setZoomLevel:16]; self.mapView.showMapScaleBar = YES; self.mapView.userTrackingMode = BMKUserTrackingModeNone; self.mapView.showsUserLocation = YES; [self.locService startUserLocationService]; CLLocationCoordinate2D coor; coor.latitude = self.latitude; coor.longitude = self.longitude; if (self.pointAnnotation == nil) { //自定義大頭針 self.pointAnnotation = [[YLAnnotationView alloc]init]; self.pointAnnotation.coordinate = coor; self.pointAnnotation.title = @"房源位置"; self.pointAnnotation.subtitle = @"點擊到這裏去"; self.pointAnnotation.image = [UIImage imageNamed:@"homelocation"]; } [self.mapView addAnnotation:self.pointAnnotation]; //設置中心點 [self.mapView setCenterCoordinate:coor]; //檢索周邊設施 self.poiSearch.delegate = self; //添加大頭針後添加周邊檢索 self.option.location = coor; self.option.pageIndex = 0; self.option.pageCapacity = 20; self.option.radius = 1500;
第四步:在點擊事件中初始化檢索對象,Demo中我自己定義了一個topView用來做不同點擊區分。
#pragma mark -- YLSelectorItemViewDelegate
- (void)didSelectedItems:(NSInteger)item {
CLLocationCoordinate2D coor;
coor.latitude = self.latitude;
coor.longitude = self.longitude;
self.seletItem = item;
self.isFirst = YES;
if (item == 1) {
self.option.keyword = @"美食";
BOOL flag = [self.poiSearch poiSearchNearBy:self.option];
if(flag) {
NSLog(@"周邊檢索發送成功");
}else {
NSLog(@"周邊檢索發送失敗");
}
}else if (item == 2) {
self.option.keyword = @"超市";
BOOL flag1 = [self.poiSearch poiSearchNearBy:self.option];
if(flag1) {
NSLog(@"周邊檢索發送成功");
}else {
}
}else if (item == 3) {
self.option.keyword = @"ATM";
BOOL flag2 = [self.poiSearch poiSearchNearBy:self.option];
if(flag2) {
NSLog(@"周邊檢索發送成功");
}else {
NSLog(@"周邊檢索發送失敗");
}
}else if (item == 4) {
self.option.keyword = @"購物";
BOOL flag3 = [self.poiSearch poiSearchNearBy:self.option];
if(flag3) {
NSLog(@"周邊檢索發送成功");
}else {
NSLog(@"周邊檢索發送失敗");
}
}
}
第五步:點擊後會進入下面這個代理,首先刪除屏幕上的大頭針,由於我這裏還是需要顯示這個房源大頭針,這裏我做了一個處理保存下來,在for循環
中拿到了所有的list
中的對象,這些對象就是我們要的周邊信息,但是並不是詳情,詳情是需要拿到這個目標對象UID
再次去檢索(這裏普通檢索和詳情檢索被百度強行分開了,可能處於流量或者模塊化的考慮吧)。那麽就必須再次創建檢索對象了,這次for循環
每次都會出現一個詳情檢索,於是我們可以到詳情代理中做事情了。
//實現PoiSearchDeleage處理回調結果
- (void)onGetPoiResult:(BMKPoiSearch *)searcher result:(BMKPoiResult *)poiResultList errorCode:(BMKSearchErrorCode)error {
// 清楚屏幕中除卻房源外的所有的annotation
NSMutableArray *array = [NSMutableArray arrayWithArray:self.mapView.annotations];
//把房源的保存下載
[array removeObjectAtIndex:0];
[self.mapView removeAnnotations:array];
array = [[NSArray arrayWithArray:self.mapView.overlays] mutableCopy];
[self.mapView removeOverlays:array];
if (error == BMK_SEARCH_NO_ERROR) {
for (int i = 0; i < poiResultList.poiInfoList.count; i++) {
BMKPoiInfo *poi = [poiResultList.poiInfoList objectAtIndex:i];
//自定義大頭針
BMKPoiDetailSearchOption *option = [[BMKPoiDetailSearchOption alloc] init];
option.poiUid = poi.uid;
BMKPoiSearch *se = [[BMKPoiSearch alloc] init];
se.delegate = self;
//把所有的POI存入數組,用於最終的釋放,避免循環引用;
[self.poiDetails addObject:se];
[se poiDetailSearch:option];
}
} else if (error == BMK_SEARCH_AMBIGUOUS_KEYWORD){
NSLog(@"搜索詞有歧義");
} else {
// 各種情況的判斷。。。
}
}
詳情代理,這裏我需要不同的大頭針圖片,做了一個處理
//周邊搜索的詳情代理
- (void)onGetPoiDetailResult:(BMKPoiSearch *)searcher result:(BMKPoiDetailResult *)poiDetailResult errorCode:(BMKSearchErrorCode)errorCode {
CLLocationCoordinate2D houseCoor;
houseCoor.latitude = self.latitude;
houseCoor.longitude = self.longitude;
if (errorCode == BMK_SEARCH_NO_ERROR) {
YLAnnotationView *item = [[YLAnnotationView alloc] init];
item.coordinate = poiDetailResult.pt;
switch (self.seletItem) {
case 1:
item.image = [UIImage imageNamed:@"food"];
item.subtitle = [NSString stringWithFormat:@"均價:%.2f",poiDetailResult.price];
break;
case 2:
item.image = [UIImage imageNamed:@"supermarket"];
item.subtitle = poiDetailResult.address;
break;
case 3:
item.image = [UIImage imageNamed:@"ATM"];
item.subtitle = poiDetailResult.address;
break;
case 4:
item.image = [UIImage imageNamed:@"shoping"];
item.subtitle = poiDetailResult.address;
break;
default:
break;
}
item.title = poiDetailResult.name;
//加個判斷,第一次進來的時候設置中心點,不能每次都移動中心,不然POI期間會拖不動地圖。
if (self.isFirst) {
[self.mapView setCenterCoordinate:houseCoor animated:YES];
}
self.isFirst = NO;
[self.mapView addAnnotation:item];
}else if (errorCode == BMK_SEARCH_AMBIGUOUS_KEYWORD) {
NSLog(@"搜索詞有歧義");
}else {
}
}
到這裏主要代碼就結束了。文末我會附上Demo
二:路徑規劃
點擊搜索,傳過來一種路線方式,並且傳來開始地與目的地。我本想直接寫出需要註意的地方,但是發現在代碼中不少都已經註釋了,請大家註意,例如 //每次必須是一個新的對象,不然pt
和name
會混亂
下面代碼有很多邏輯上的處理,為了一體性,我沒有刪去。
#pragma mark -- RoutePlanViewDelegate
//搜路線
- (void)didSelectorItems:(NSInteger)item withStartName:(NSString *)startName andEndName:(NSString *)endName {
CLLocationCoordinate2D houseCoor;
houseCoor.latitude = self.latitude;
houseCoor.longitude = self.longitude;
//每次必須是一個新的對象,不然pt和name會混亂
self.startNode = [[BMKPlanNode alloc] init];
self.endNode = [[BMKPlanNode alloc] init];
self.startNode.cityName = @"南京";
self.endNode.cityName = @"南京";
//設置出發點與終點
if ([startName isEqualToString:@""] || [endName isEqualToString:@""]) {
NSLog(@"搜索字段有歧義");
return;
}
if ([startName isEqualToString:@"當前位置"] && [endName isEqualToString:@"房源位置"]) {
self.startNode.pt = self.userLocation.location.coordinate;
self.endNode.pt = houseCoor;
}else if ([endName isEqualToString:@"當前位置"] && [startName isEqualToString:@"房源位置"]) {
self.startNode.pt = houseCoor;
self.endNode.pt = self.userLocation.location.coordinate;
}else if (![startName isEqualToString:@"當前位置"] && [endName isEqualToString:@"房源位置"]) {
self.startNode.name = startName;
self.endNode.pt = houseCoor;
}else if([startName isEqualToString:@"當前位置"] && ![endName isEqualToString:@"房源位置"]) {
self.startNode.pt = self.userLocation.location.coordinate;
self.endNode.name = endName;
}else if(![startName isEqualToString:@"當前位置"] && [endName isEqualToString:@"當前位置"]) {
self.startNode.name = startName;
self.endNode.pt = self.userLocation.location.coordinate;
}else if([startName isEqualToString:@"房源位置"] && ![endName isEqualToString:@"當前位置"]) {
self.startNode.pt = houseCoor;
self.endNode.name = endName;
}else {
self.startNode.name = startName;
self.endNode.name = endName;
}
NSLog(@"%@ ---- %@",self.startNode.name,self.endNode.name);
if (item == 1) {
//駕車
BMKDrivingRoutePlanOption *driveRouteSearchOption =[[BMKDrivingRoutePlanOption alloc]init];
driveRouteSearchOption.from = self.startNode;
driveRouteSearchOption.to = self.endNode;
BOOL flag = [self.routeSearch drivingSearch:driveRouteSearchOption];
if (flag) {
}else {
}
}else if (item == 2) {
//公交
BMKMassTransitRoutePlanOption *option = [[BMKMassTransitRoutePlanOption alloc]init];
option.from = self.startNode;
option.to = self.endNode;
BOOL flag = [self.routeSearch massTransitSearch:option];
if(flag) {
NSLog(@"公交交通檢索(支持垮城)發送成功");
} else {
NSLog(@"公交交通檢索(支持垮城)發送失敗");
}
} else if (item == 3) {
//步行
BMKWalkingRoutePlanOption *walkingRouteSearchOption = [[BMKWalkingRoutePlanOption alloc] init];
walkingRouteSearchOption.from = self.startNode;
walkingRouteSearchOption.to = self.endNode;
BOOL flag = [self.routeSearch walkingSearch:walkingRouteSearchOption];
if(flag) {
NSLog(@"walk檢索發送成功");
}else {
NSLog(@"walk檢索發送失敗");
}
}else {
//騎車
BMKRidingRoutePlanOption *option = [[BMKRidingRoutePlanOption alloc]init];
option.from = self.startNode;
option.to = self.endNode;
BOOL flag = [self.routeSearch ridingSearch:option];
if (flag) {
NSLog(@"騎行規劃檢索發送成功");
}else {
NSLog(@"騎行規劃檢索發送失敗");
}
}
}
點擊後,會進入下面這個代理
#pragma mark -- BMKRouteSearchDelegate
//駕車
- (void)onGetDrivingRouteResult:(BMKRouteSearch *)searcher result:(BMKDrivingRouteResult *)result errorCode:(BMKSearchErrorCode)error {
NSMutableArray *array = [NSMutableArray arrayWithArray:self.mapView.annotations];
[array removeObjectAtIndex:0];
[self.mapView removeAnnotations:array];
array = [[NSArray arrayWithArray:self.mapView.overlays] mutableCopy];
[self.mapView removeOverlays:array];
if (error == BMK_SEARCH_NO_ERROR) {
//表示一條駕車路線
BMKDrivingRouteLine *plan = (BMKDrivingRouteLine *)[result.routes objectAtIndex:0];
// 計算路線方案中的路段數目
int size = (int)[plan.steps count];
int planPointCounts = 0;
for (int i = 0; i < size; i++) {
//表示駕車路線中的一個路段
BMKDrivingStep *transitStep = [plan.steps objectAtIndex:i];
if(i==0){
RouteAnnotation *item = [[RouteAnnotation alloc]init];
item.coordinate = plan.starting.location;
item.title = @"起點";
item.type = 0;
[self.mapView addAnnotation:item]; // 添加起點標註
}else if(i==size-1){
RouteAnnotation *item = [[RouteAnnotation alloc]init];
item.coordinate = plan.terminal.location;
item.title = @"終點";
item.type = 1;
[self.mapView addAnnotation:item]; // 添加終點標註
}
//添加annotation節點
RouteAnnotation *item = [[RouteAnnotation alloc]init];
item.coordinate = transitStep.entrace.location;
item.title = transitStep.entraceInstruction;
item.degree = transitStep.direction *30;
item.type = 4;
[self.mapView addAnnotation:item];
//軌跡點總數累計
planPointCounts += transitStep.pointsCount;
}
// 添加途經點
if (plan.wayPoints) {
for (BMKPlanNode *tempNode in plan.wayPoints) {
RouteAnnotation *item = [[RouteAnnotation alloc]init];
item.coordinate = tempNode.pt;
item.type = 5;
item.title = tempNode.name;
[self.mapView addAnnotation:item];
}
}
//軌跡點
BMKMapPoint *temppoints = new BMKMapPoint[planPointCounts];
int i = 0;
for (int j = 0; j < size; j++) {
BMKDrivingStep *transitStep = [plan.steps objectAtIndex:j];
int k=0;
for(k=0;k<transitStep.pointsCount;k++) {
temppoints[i].x = transitStep.points[k].x;
temppoints[i].y = transitStep.points[k].y;
i++;
}
}
// 通過points構建BMKPolyline
BMKPolyline *polyLine = [BMKPolyline polylineWithPoints:temppoints count:planPointCounts];
[self.mapView addOverlay:polyLine]; // 添加路線overlay
delete []temppoints;
[self mapViewFitPolyLine:polyLine];
}
}
上面我僅僅放了一個駕車的代理,還有步行等沒有放上去,太長了,文末為了不想下載代碼的同學觀看,我會放上整頁代碼提供參考。
言歸正傳,你們發現我有自定義了一個RouteAnnotation
類。這個路線需要字段比較多,我不想改動之前大頭針類了,就直接重寫了一個。如下
/**
* 路線的標註 自定義一個大頭針類 為了便捷,就直接放這裏了
*/
@interface RouteAnnotation : BMKPointAnnotation {
int _type; ///<0:起點 1:終點 2:公交 3:地鐵 4:駕乘 5:途經點
int _degree;//旋轉的角度
}
@property (nonatomic) int type;
@property (nonatomic) int degree;
@end
@implementation RouteAnnotation
@synthesize type = _type;
@synthesize degree = _degree;
@end
如果你也這樣做,那麽就像我一樣在大頭針重用方法中做以下判斷,並且實現這個方法,如下:
if ([annotation isKindOfClass:[RouteAnnotation class]]) {
return [self getRouteAnnotationView:view viewForAnnotation:(RouteAnnotation *)annotation];
}
#pragma mark -- 獲取路線的標註,顯示到地圖(自定義的一個大頭針類實例方法)我只貼到case 0;其他的在文末查找,需要註意的地方我已寫註釋
- (BMKAnnotationView *)getRouteAnnotationView:(BMKMapView *)mapview viewForAnnotation:(RouteAnnotation *)routeAnnotation {
BMKAnnotationView *view = nil;
//根據大頭針類型判斷是什麽圖標
switch (routeAnnotation.type) {
case 0:
{ //開始點
view = [mapview dequeueReusableAnnotationViewWithIdentifier:@"start_node"];
if (view == nil) {
view = [[BMKAnnotationView alloc] initWithAnnotation:routeAnnotation reuseIdentifier:@"start_node"];
//從百度地圖資源文件中拿到需要的圖片
view.image = [UIImage imageWithContentsOfFile:[self getMyBundlePath1:@"images/icon_nav_start"]];
view.centerOffset = CGPointMake(0, -(view.frame.size.height * 0.5));
view.canShowCallout = true;
}
view.annotation = routeAnnotation;
}
在駕車路線的代理最後我們添加了一條線,就是如下代碼
// 通過points構建BMKPolyline
BMKPolyline *polyLine = [BMKPolyline polylineWithPoints:temppoints count:planPointCounts];
[self.mapView addOverlay:polyLine]; // 添加路線overlay
delete []temppoints;
[self mapViewFitPolyLine:polyLine];
這樣我們還需要實現一個劃線的代理,這個是必須實現的。還有一個地圖路線的範圍計算,文末的所有代碼中的最後一段,這些都是從百度地圖官方代碼拿來的。
#pragma mark -- 路線線條繪制代理
- (BMKOverlayView *)mapView:(BMKMapView *)map viewForOverlay:(id<BMKOverlay>)overlay {
if ([overlay isKindOfClass:[BMKPolyline class]]) {
BMKPolylineView *polylineView = [[BMKPolylineView alloc] initWithOverlay:overlay];
//設置線條顏色
polylineView.fillColor = [[UIColor alloc] initWithRed:0 green:1 blue:1 alpha:1];
polylineView.strokeColor = [[UIColor alloc] initWithRed:0 green:0 blue:0.8 alpha:0.7];
polylineView.lineWidth = 3.0;
return polylineView;
}
return nil;
}
雖然上面大多都是復制粘貼把,但是 Demo
代碼都是我用心準備的,這裏也主要是說個流程。
三、運行效果
四、其他補充
百度地圖的集成很簡單,按照開發文檔幾分鐘就搞定了,我就不抄寫了,但是記錄幾個可能會出問題的地方吧。
- Privacy - Location Always Usage Description plist.info請求使用GPS
- LSApplicationQueriesSchemes 如果你需要調起百度地圖客戶端
- Bundle display name plist.info中需要加入,而且是必要的
- 這個文件用到了c++代碼,請務必把文件後綴名改為.mm
百度地圖檢索以及路徑規劃代碼地址如下:<br>http://www.demodashi.com/demo/11030.html
註:本文著作權歸作者,由demo大師代發,拒絕轉載,轉載需要作者授權
百度地圖檢索以及路徑規劃