先去百度地圖開發者中心申請APPkey:http://developer.baidu.com/map/index.php?title=iossdk ,下載百度地圖的SDK。
匯入SDK的framework檔案,BaiduMapAPI_Base.framework是基礎包,是必須要匯入的,根據自己的需求匯入需要的百度SDK的framework,新版的SDK已經可以選擇下載哪些framework,減小了包的大小。
引入所需的系統庫,在Xcode工程中引入
CoreLocation.framework
                    QuartzCore.framework
                    OpenGLES.framework
                    SystemConfiguration.framework
                    CoreGraphics.framework
                    Security.framework
                    libsqlite3.0.tbd(xcode7以前為 libsqlite3.0.dylib)
                    CoreTelephony.framework
                    libstdc++.6.0.9.tbd(xcode7以前為libstdc++.6.0.9.dylib)
複製程式碼
根據需求引入標頭檔案,我們只要定位,搜尋和路線繪製,所以不必要全部引入。
#import <BaiduMapAPI_Base/BMKBaseComponent.h>//引入base相關所有的標頭檔案
#import <BaiduMapAPI_Map/BMKMapComponent.h>//引入地圖功能所有的標頭檔案
#import <BaiduMapAPI_Search/BMKSearchComponent.h>//引入檢索功能所有的標頭檔案
#import <BaiduMapAPI_Cloud/BMKCloudSearchComponent.h>//引入雲檢索功能所有的標頭檔案
#import <BaiduMapAPI_Location/BMKLocationComponent.h>//引入定位功能所有的標頭檔案
#import <BaiduMapAPI_Utils/BMKUtilsComponent.h>//引入計算工具所有的標頭檔案
#import <BaiduMapAPI_Radar/BMKRadarComponent.h>//引入周邊雷達功能所有的標頭檔案
#import < BaiduMapAPI_Map/BMKMapView.h>//只引入所需的單個標頭檔案
複製程式碼
下面開始進行程式碼的實踐:
首先引用代理方法:
BMKMapViewDelegate//基礎代理
BMKRouteSearchDelegate//搜尋代理
BMKLocationServiceDelegate//定位代理
BMKGeoCodeSearchDelegate//地理反編碼代理
複製程式碼
定義宣告檔案:
@interface RouteSearchDemoViewController : BaseViewCtrl<BMKMapViewDelegate, BMKRouteSearchDelegate,BMKLocationServiceDelegate,BMKGeoCodeSearchDelegate> {
IBOutlet BMKMapView* _mapView;//地圖view
IBOutlet UITextField* _startCityText;//開始的城市
IBOutlet UITextField* _startAddrText;//開始的位置
IBOutlet UITextField* _endCityText;//終點城市
IBOutlet UITextField* _endAddrText;//終點位置
BMKRouteSearch* _routesearch;//搜尋
BMKLocationService *locService;//定位
}
-(IBAction)onClickBusSearch;//公交路線
-(IBAction)onClickDriveSearch;//開車路線
-(IBAction)onClickWalkSearch;//不行路線
- (IBAction)textFiledReturnEditing:(id)sender;
@property(nonatomic,retain)MapAlertView *mapview;//一個遮蓋view
@end
複製程式碼
使用的是類中使用了XIB檔案,所以根據自己的需要進行控制元件的拖放、位置及大小設定。
在實現檔案中新增一個圖片出的函式,有些路線的繪製和圖示的變化需要用到(百度的Demo中就有這個函式)
@implementation UIImage(InternalMethod)
- (UIImage*)imageRotatedByDegrees:(CGFloat)degrees
{
CGFloat width = CGImageGetWidth(self.CGImage);
CGFloat height = CGImageGetHeight(self.CGImage);
CGSize rotatedSize;
rotatedSize.width = width;
rotatedSize.height = height;
UIGraphicsBeginImageContext(rotatedSize);
CGContextRef bitmap = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(bitmap, rotatedSize.width/2, rotatedSize.height/2);
CGContextRotateCTM(bitmap, degrees * M_PI / 180);
CGContextRotateCTM(bitmap, M_PI);
CGContextScaleCTM(bitmap, -1.0, 1.0);
CGContextDrawImage(bitmap, CGRectMake(-rotatedSize.width/2, -rotatedSize.height/2, rotatedSize.width, rotatedSize.height), self.CGImage);
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
@end
複製程式碼
下面就到了地圖的真正實施階段: 封裝一個獲取資原始檔的函式,從百度的bundle中獲取圖片等等:
- (void)viewDidLoad {
[super viewDidLoad];
//適配ios7
if( ([[[UIDevice currentDevice] systemVersion] doubleValue]>=7.0))
{
self.navigationController.navigationBar.translucent = NO;
}
_routesearch = [[BMKRouteSearch alloc] init];
_routesearch.delegate = self;
[_mapView setZoomEnabled:YES];
[_mapView setZoomLevel:13];//級別,3-19
_mapView.showMapScaleBar = YES;//比例尺
_mapView.mapScaleBarPosition = CGPointMake(10,_mapView.frame.size.height-45);//比例尺的位置
_mapView.showsUserLocation=YES;//顯示當前裝置的位置
_mapView.userTrackingMode = BMKUserTrackingModeFollow;//定位跟隨模式
_mapView.delegate = self;
[_mapView setMapType:BMKMapTypeStandard];//地圖的樣式(標準地圖)
//定位
locService = [[BMKLocationService alloc] init];
locService.delegate = self;
//啟動LocationService
[locService startUserLocationService];
}
複製程式碼
開始定位,並且地理反編碼,獲取到位置資訊:
/**
* 更新定位資訊
*
* @param userLocation 獲取到的位置資料
*/
-(void)didUpdateBMKUserLocation:(BMKUserLocation *)userLocation {
CLLocationCoordinate2D coordinate = userLocation.location.coordinate;
// 縮放
BMKCoordinateSpan span = BMKCoordinateSpanMake(0.1, 0.1);
BMKCoordinateRegion region = BMKCoordinateRegionMake(coordinate, span);
[_mapView setRegion:region];
BMKReverseGeoCodeOption *option = [[BMKReverseGeoCodeOption alloc] init];
option.reverseGeoPoint = CLLocationCoordinate2DMake(userLocation.location.coordinate.latitude, userLocation.location.coordinate.longitude);
BMKGeoCodeSearch *geoCode = [[BMKGeoCodeSearch alloc] init];
geoCode.delegate = self;
[geoCode reverseGeoCode:option];
[option release];
[geoCode release];
}
/**
* 反編碼地理位置返回代理
*
* @param result 返回結果
*/
-(void)onGetReverseGeoCodeResult:(BMKGeoCodeSearch *)searcher result:(BMKReverseGeoCodeResult *)result errorCode:(BMKSearchErrorCode)error {
if (result) {
_startCityText.text = result.addressDetail.city;;
_startAddrText.text = result.addressDetail.streetName;
//已經獲取到經緯度,可以停止定位服務
[locService stopUserLocationService];
}
}
複製程式碼
經過上面的兩個函式,已經可以獲取到所在的城市跟位置地址,具體更加詳細的資訊,可以在addressDetail中看到,一般就是所在的區,街道,街道號碼等。
在view上自己新增一個按鈕,當點選的時候彈出一個自定義alertview,上面有三個按鈕,分別是公交,行車,步行,並且新增一個手勢,點選按鈕之外的地方,remove或者隱藏alertview。
點選需要進行的導航線路繪製,有對應的搜尋類:
-(IBAction)onClickBusSearch
{
if ([_startCityText.text isEqualToString:@""]) {
[self AddStatusLabelWithText:@"正在獲取位置"];
return;
}
[self.mapview removeFromSuperview];
BMKPlanNode* start = [[[BMKPlanNode alloc]init] autorelease];
start.name = _startAddrText.text;
BMKPlanNode* end = [[[BMKPlanNode alloc]init] autorelease];
end.name = _endAddrText.text;
//公交
BMKTransitRoutePlanOption *transitRouteSearchOption = [[BMKTransitRoutePlanOption alloc]init];
transitRouteSearchOption.city = _startCityText.text;
transitRouteSearchOption.from = start;
transitRouteSearchOption.to = end;
BOOL flag = [_routesearch transitSearch:transitRouteSearchOption];
[transitRouteSearchOption release];
if(flag)
{
NSLog(@"bus檢索傳送成功");
}
else
{
NSLog(@"bus檢索傳送失敗");
}
}
-(IBAction)onClickDriveSearch
{
if ([_startCityText.text isEqualToString:@""]) {
[self AddStatusLabelWithText:@"正在獲取位置"];
return;
}
[self.mapview removeFromSuperview];
BMKPlanNode* start = [[[BMKPlanNode alloc]init] autorelease];
start.name = _startAddrText.text;
BMKPlanNode* end = [[[BMKPlanNode alloc]init] autorelease];
end.name = _endAddrText.text;
/// 駕車查詢基礎資訊類
BMKDrivingRoutePlanOption *drivingRouteSearchOption = [[BMKDrivingRoutePlanOption alloc]init];
drivingRouteSearchOption.from = start;
drivingRouteSearchOption.to = end;
BOOL flag = [_routesearch drivingSearch:drivingRouteSearchOption];
[drivingRouteSearchOption release];
if(flag)
{
NSLog(@"car檢索傳送成功");
}
else
{
NSLog(@"car檢索傳送失敗");
}
}
-(IBAction)onClickWalkSearch
{
if ([_startCityText.text isEqualToString:@""]) {
[self AddStatusLabelWithText:@"正在獲取位置"];
return;
}
[self.mapview removeFromSuperview];
BMKPlanNode* start = [[[BMKPlanNode alloc]init] autorelease];
start.name = _startAddrText.text;
BMKPlanNode* end = [[[BMKPlanNode alloc]init] autorelease];
end.name = _endAddrText.text;
/// 步行查詢基礎資訊類
BMKWalkingRoutePlanOption *walkingRouteSearchOption = [[BMKWalkingRoutePlanOption alloc]init];
walkingRouteSearchOption.from = start;
walkingRouteSearchOption.to = end;
BOOL flag = [_routesearch walkingSearch:walkingRouteSearchOption];
[walkingRouteSearchOption release];
if(flag)
{
NSLog(@"walk檢索傳送成功");
}
else
{
NSLog(@"walk檢索傳送失敗");
}
}
複製程式碼
每個start的城市和地址都可以設定,其中公交線路的start城市和transitRouteSearchOption的城市是必須要有的,否則會檢索失敗或者檢索不到線路;
傳送檢索成功後會回撥對應的繪製線路代理方法:
- (void)onGetTransitRouteResult:(BMKRouteSearch*)searcher result:(BMKTransitRouteResult*)result errorCode:(BMKSearchErrorCode)error
{
MapExplainViewController *exp=[[[MapExplainViewController alloc]init]autorelease];
exp.array=result.routes;
[self.navigationController pushViewController:exp animated:YES];
NSArray* array = [NSArray arrayWithArray:_mapView.annotations];
[_mapView removeAnnotations:array];
array = [NSArray arrayWithArray:_mapView.overlays];
[_mapView removeOverlays:array];
if (error == BMK_SEARCH_NO_ERROR) {
BMKTransitRouteLine* plan = (BMKTransitRouteLine*)[result.routes objectAtIndex:0];
// 計算路線方案中的路段數目
int size = [plan.steps count];
int planPointCounts = 0;
for (int i = 0; i < size; i++) {
BMKTransitStep* transitStep = [plan.steps objectAtIndex:i];
if(i==0){
RouteAnnotation* item = [[RouteAnnotation alloc]init];
item.coordinate = plan.starting.location;
item.title = @"起點";
item.type = 0;
[_mapView addAnnotation:item]; // 新增起點標註
[item release];
}else if(i==size-1){
RouteAnnotation* item = [[RouteAnnotation alloc]init];
item.coordinate = plan.terminal.location;
item.title = @"終點";
item.type = 1;
[_mapView addAnnotation:item]; // 新增起點標註
[item release];
}
RouteAnnotation* item = [[RouteAnnotation alloc]init];
item.coordinate = transitStep.entrace.location;
item.title = transitStep.instruction;
item.type = 3;
[_mapView addAnnotation:item];
[item release];
//軌跡點總數累計
planPointCounts += transitStep.pointsCount;
}
//軌跡點
BMKMapPoint * temppoints = new BMKMapPoint[planPointCounts];
int i = 0;
for (int j = 0; j < size; j++) {
BMKTransitStep* 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];
[_mapView addOverlay:polyLine]; // 新增路線overlay
delete []temppoints;
}
}
//駕車的路線繪製
- (void)onGetDrivingRouteResult:(BMKRouteSearch*)searcher result:(BMKDrivingRouteResult*)result errorCode:(BMKSearchErrorCode)error
{
MapExplainViewController *exp=[[[MapExplainViewController alloc]init]autorelease];
exp.array=result.routes;
[self.navigationController pushViewController:exp animated:YES];
NSArray* array = [NSArray arrayWithArray:_mapView.annotations];
[_mapView removeAnnotations:array];
array = [NSArray arrayWithArray:_mapView.overlays];
[_mapView removeOverlays:array];
if (error == BMK_SEARCH_NO_ERROR) {
BMKDrivingRouteLine* plan = (BMKDrivingRouteLine*)[result.routes objectAtIndex:0];
// 計算路線方案中的路段數目
int size = [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;
[_mapView addAnnotation:item]; // 新增起點標註
[item release];
}else if(i==size-1){
RouteAnnotation* item = [[RouteAnnotation alloc]init];
item.coordinate = plan.terminal.location;
item.title = @"終點";
item.type = 1;
[_mapView addAnnotation:item]; // 新增起點標註
[item release];
}
//新增annotation節點
RouteAnnotation* item = [[RouteAnnotation alloc]init];
item.coordinate = transitStep.entrace.location;
item.title = transitStep.entraceInstruction;
item.degree = transitStep.direction * 30;
item.type = 4;
[_mapView addAnnotation:item];
[item release];
//軌跡點總數累計
planPointCounts += transitStep.pointsCount;
}
// 新增途經點
if (plan.wayPoints) {
for (BMKPlanNode* tempNode in plan.wayPoints) {
RouteAnnotation* item = [[RouteAnnotation alloc]init];
item = [[RouteAnnotation alloc]init];
item.coordinate = tempNode.pt;
item.type = 5;
item.title = tempNode.name;
[_mapView addAnnotation:item];
[item release];
}
}
//軌跡點
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];
[_mapView addOverlay:polyLine]; // 新增路線overlay
delete []temppoints;
}
}
//步行的路線繪製
- (void)onGetWalkingRouteResult:(BMKRouteSearch*)searcher result:(BMKWalkingRouteResult*)result errorCode:(BMKSearchErrorCode)error
{
MapExplainViewController *exp=[[[MapExplainViewController alloc]init]
autorelease];
exp.array=result.routes;
[self.navigationController pushViewController:exp animated:YES];
NSArray* array = [NSArray arrayWithArray:_mapView.annotations];
[_mapView removeAnnotations:array];
array = [NSArray arrayWithArray:_mapView.overlays];
[_mapView removeOverlays:array];
if (error == BMK_SEARCH_NO_ERROR) {
BMKWalkingRouteLine* plan = (BMKWalkingRouteLine*)[result.routes objectAtIndex:0];
int size = [plan.steps count];
int planPointCounts = 0;
for (int i = 0; i < size; i++) {
BMKWalkingStep* transitStep = [plan.steps objectAtIndex:i];
if(i==0){
RouteAnnotation* item = [[RouteAnnotation alloc]init];
item.coordinate = plan.starting.location;
item.title = @"起點";
item.type = 0;
[_mapView addAnnotation:item]; // 新增起點標註
[item release];
}else if(i==size-1){
RouteAnnotation* item = [[RouteAnnotation alloc]init];
item.coordinate = plan.terminal.location;
item.title = @"終點";
item.type = 1;
[_mapView addAnnotation:item]; // 新增起點標註
[item release];
}
//新增annotation節點
RouteAnnotation* item = [[RouteAnnotation alloc]init];
item.coordinate = transitStep.entrace.location;
item.title = transitStep.entraceInstruction;
item.degree = transitStep.direction * 30;
item.type = 4;
[_mapView addAnnotation:item];
[item release];
//軌跡點總數累計
planPointCounts += transitStep.pointsCount;
}
//軌跡點
BMKMapPoint * temppoints = new BMKMapPoint[planPointCounts];
int i = 0;
for (int j = 0; j < size; j++) {
BMKWalkingStep* 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];
[_mapView addOverlay:polyLine]; // 新增路線overlay
delete []temppoints;
}
}
複製程式碼
搜尋的回撥代理成功後,需要在mapview 上繪製線條:
///<0:起點 1:終點 2:公交 3:地鐵 4:駕乘 5:途經點
- (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"] autorelease];
view.image = [UIImage imageWithContentsOfFile:[self getMyBundlePath1:@"images/icon_nav_start.png"]];
view.centerOffset = CGPointMake(0, -(view.frame.size.height * 0.5));
view.canShowCallout = TRUE;
}
view.annotation = routeAnnotation;
}
break;
case 1:
{
view = [mapview dequeueReusableAnnotationViewWithIdentifier:@"end_node"];
if (view == nil) {
view = [[[BMKAnnotationView alloc]initWithAnnotation:routeAnnotation reuseIdentifier:@"end_node"] autorelease];
view.image = [UIImage imageWithContentsOfFile:[self getMyBundlePath1:@"images/icon_nav_end.png"]];
view.centerOffset = CGPointMake(0, -(view.frame.size.height * 0.5));
view.canShowCallout = TRUE;
}
view.annotation = routeAnnotation;
}
break;
case 2:
{
view = [mapview dequeueReusableAnnotationViewWithIdentifier:@"bus_node"];
if (view == nil) {
view = [[[BMKAnnotationView alloc]initWithAnnotation:routeAnnotation reuseIdentifier:@"bus_node"] autorelease];
view.image = [UIImage imageWithContentsOfFile:[self getMyBundlePath1:@"images/icon_nav_bus.png"]];
view.canShowCallout = TRUE;
}
view.annotation = routeAnnotation;
}
break;
case 3:
{
view = [mapview dequeueReusableAnnotationViewWithIdentifier:@"rail_node"];
if (view == nil) {
view = [[[BMKAnnotationView alloc]initWithAnnotation:routeAnnotation reuseIdentifier:@"rail_node"] autorelease];
view.image = [UIImage imageWithContentsOfFile:[self getMyBundlePath1:@"images/icon_nav_rail.png"]];
view.canShowCallout = TRUE;
}
view.annotation = routeAnnotation;
}
break;
case 4:
{
view = [mapview dequeueReusableAnnotationViewWithIdentifier:@"route_node"];
if (view == nil) {
view = [[[BMKAnnotationView alloc]initWithAnnotation:routeAnnotation reuseIdentifier:@"route_node"] autorelease];
view.canShowCallout = TRUE;
} else {
[view setNeedsDisplay];
}
UIImage* image = [UIImage imageWithContentsOfFile:[self getMyBundlePath1:@"images/icon_direction.png"]];
view.image = [image imageRotatedByDegrees:routeAnnotation.degree];
view.annotation = routeAnnotation;
}
break;
case 5:
{
view = [mapview dequeueReusableAnnotationViewWithIdentifier:@"waypoint_node"];
if (view == nil) {
view = [[[BMKAnnotationView alloc]initWithAnnotation:routeAnnotation reuseIdentifier:@"waypoint_node"] autorelease];
view.canShowCallout = TRUE;
} else {
[view setNeedsDisplay];
}
UIImage* image = [UIImage imageWithContentsOfFile:[self getMyBundlePath1:@"images/icon_nav_waypoint.png"]];
view.image = [image imageRotatedByDegrees:routeAnnotation.degree];
view.annotation = routeAnnotation;
}
break;
default:
break;
}
return view;
}
- (BMKAnnotationView *)mapView:(BMKMapView *)view viewForAnnotation:(id <BMKAnnotation>)annotation
{
if ([annotation isKindOfClass:[RouteAnnotation class]]) {
return [self getRouteAnnotationView:view viewForAnnotation:(RouteAnnotation*)annotation];
}
return nil;
}
//載入線路
- (BMKOverlayView*)mapView:(BMKMapView *)map viewForOverlay:(id<BMKOverlay>)overlay
{
if ([overlay isKindOfClass:[BMKPolyline class]]) {
BMKPolylineView* polylineView = [[[BMKPolylineView alloc] initWithOverlay:overlay] autorelease];
polylineView.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:1];
polylineView.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7];
polylineView.lineWidth = 3.0;
return polylineView;
}
return nil;
}
複製程式碼
經過以上方法,基本上在mapview上就可以看到線路導航圖,如果不行,可以那些錯誤列舉去檢視原因,畢竟百度是中國的,所以SDK裡的註釋都是中文,對於英文渣渣的我來說,簡直太幸福了。
還有一個地方使用了百度定位來獲取天氣資訊,比系統的地理反編碼快很多,很快就獲取到了所在位置的城市。
同樣的天氣api使用的是百度天氣,返回的資料裡直接就有對應天氣的圖片的url,雖然圖片很醜,但是總比沒有的強,下面是百度天氣的api地址:
-(void)WeatherRequest
{
[self ShowWaitView:@"正在載入中。。。"];
//[GlobalData GetInstance].GB_CityString 是自己獲取到城市
NSString *str = [[GlobalData GetInstance].GB_CityString URLEncoding];
//用定位的城市請求 ak是自己申請的百度金鑰
NSString *strurl=[NSString stringWithFormat:@"http://api.map.baidu.com/telematics/v3/weather?location=%@&output=json&ak=C3d2845360d091a5e8f42f605b7472ea",str];
ASIFormDataRequest *weatherRequest = [[ASIFormDataRequest alloc] initWithURL:[NSURL URLWithString:strurl]];
weatherRequest.delegate = self;
[weatherRequest startAsynchronous];
}
複製程式碼