iOS经典讲解之百度地图的使用及案例(iOS地图SDK)

准备工作:

一、去百度开发平台注册,并且获得密钥,具体步骤百度开发平台详细说明,并且下载相应的BaiduMapAPI.framework。

二、引入BaiduMapAPI.framework

将所需的BaiduMapAPI.framework拷贝到工程所在文件夹下。在 TARGETS->Build Phases-> Link Binary With Libaries中点击“+”按钮,在弹出的窗口中点击“Add Other”按钮,选择BaiduMapAPI.framework文件添加到工程中。

三、引入所需的系统库

百度地图SDK中提供了定位功能和动画效果,v2.0.0版本开始使用OpenGL渲染,因此您需要在您的Xcode工程中引入CoreLocation.framework和QuartzCore.framework、OpenGLES.framework、SystemConfiguration.framework、CoreGraphics.framework、Security.framework。添加方式:在Xcode的Project -> Active Target ->Build Phases ->Link Binary With Libraries,添加这几个framework即可。

四、环境配置

在TARGETS->Build Settings->Other Linker Flags 中添加-ObjC。

五、引入mapapi.bundle资源文件

如果使用了基础地图功能,需要添加该资源,否则地图不能正常显示

方法:选中工程名,在右键菜单中选择Add Files to “工程名”…,从BaiduMapAPI.framework||Resources文件中选择mapapi.bundle文件,并勾选“Copy items if needed”复选框,单击“Add”按钮,将资源文件添加到工程中。

六、引入头文件

在使用SDK的类引入头文件:

#import <BaiduMapAPI/BMapKit.h>//引入所有的头文件
 
#import <BaiduMapAPI/BMKMapView.h>//只引入所需的单个头文件

七、在info.plist文件中添加

NSLocationWhenInUseUsageDescription

NSLocationAlwaysUsageDescription

Bundle display name等字段。因为百度提供的类中使用了

- (void)requestWhenInUseAuthorization

- (void)requestAlwaysAuthorization,方法。具体原因详见 iOS经典讲解之地图定位请求位置信息时出现的问题

如图所示:


准备工作完成后,下面是具体示例代码:

//
//  ViewController.m
//  BaiDuMapSample
#import "ViewController.h"
#import <BaiduMapAPI/BMapKit.h>
@interface ViewController () <BMKGeneralDelegate, BMKMapViewDelegate, BMKLocationServiceDelegate, BMKGeoCodeSearchDelegate, BMKRouteSearchDelegate>
// 开始城市
@property (nonatomic, strong) UITextField *startCityTF;
// 开始地址
@property (nonatomic, strong) UITextField *startAddressTF;
// 终点城市
@property (nonatomic,strong) UITextField *endCityTF;
// 终点地址
@property (nonatomic, strong) UITextField *endAddressTF;
// 添加地图
@property (nonatomic, strong) BMKMapView *mapView;
// 定位服务对象(专门用于定位)
@property (nonatomic, strong) BMKLocationService *locationService;
//声明地理位置搜索对象(负责地理编码)
@property (nonatomic, strong) BMKGeoCodeSearch *geocoder;
// 声明路线搜索服务对象
@property (nonatomic, strong) BMKRouteSearch *routeSearch;
// 开始路线检索节点
@property (nonatomic, strong) BMKPlanNode *statNode;
// 目标路线检索节点
@property (nonatomic, strong) BMKPlanNode *endNode;

@end

@implementation ViewController
-(void)dealloc
{
    self.geocoder.delegate = nil;
    self.locationService.delegate = nil;
    self.mapView.delegate = nil;
    self.routeSearch.delegate = nil;

}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 因为百度SDK的引擎是使用C++代码写成,所以我们必须保证我们的工程中至少有一个文件是.mm后缀
    // 创建百度地图主引擎类(使用百度地图功能之前必须启动引擎)
    BMKMapManager *manager = [[BMKMapManager alloc] init];
    // 启动引擎
    // foIpeFfSSd5SGy2fKxLmD0M8百度开发者平台注册的密钥
    // 注意要把NSLocationWhenInUseUsageDescription NSLocationAlwaysUsageDescription 字段添加到plist文件中
    [manager start:@"foIpeFfSSd5SGy2fKxLmD0M8" generalDelegate:self];
    
    
    // 设置内边距
    if ([[UIDevice currentDevice].systemVersion floatValue] >= 7.0) {
        self.edgesForExtendedLayout = UIRectEdgeNone;
    }
    
    // 搭建UI
    [self addSubViews];
    
    // 创建定位服务对象
    self.locationService = [[BMKLocationService alloc] init];
    // 设置定位服务对象的代理
    self.locationService.delegate = self;
    // 设置再次定位的最小距离
    [BMKLocationService setLocationDistanceFilter:10];
    
    
    // 创建地理位置搜索对象
    self.geocoder = [[BMKGeoCodeSearch alloc] init];
    // 设置代理
    self.geocoder.delegate = self;
    
    
    // 创建routeSearch服务对象
    self.routeSearch = [[BMKRouteSearch alloc] init];
    // 设置代理
    self.routeSearch.delegate = self;
    
}

/**
 *  搭建UI方法
 */

- (void)addSubViews
{
    // 设置barButtonItem
    UIBarButtonItem *leftButton = [[UIBarButtonItem alloc] initWithTitle:@"开始定位" style:(UIBarButtonItemStylePlain) target:self action:@selector(leftAction:)];
    self.navigationItem.leftBarButtonItem = leftButton;
    
    UIBarButtonItem *rightButton = [[UIBarButtonItem alloc] initWithTitle:@"关闭定位" style:(UIBarButtonItemStylePlain) target:self action:@selector(rightAction:)];
    self.navigationItem.rightBarButtonItem = rightButton;
    
    // 设置textField
    // 开始城市
    self.startCityTF = [[UITextField alloc] initWithFrame:CGRectMake(20, 30, 100, 30)];
    self.startCityTF.text = @"开始城市";
    [self.view addSubview:self.startCityTF];
    // 开始地址
    self.startAddressTF = [[UITextField alloc] initWithFrame:CGRectMake(CGRectGetMaxX(self.startCityTF.frame) + 30, CGRectGetMinY(self.startCityTF.frame), CGRectGetWidth(self.startCityTF.frame), CGRectGetHeight(self.startCityTF.frame))];
    self.startAddressTF.text = @"开始地址";
    [self.view addSubview:self.startAddressTF];
    // 目的城市
    self.endCityTF = [[UITextField alloc] initWithFrame:CGRectMake(CGRectGetMinX(self.startCityTF.frame), CGRectGetMaxY(self.startCityTF.frame) + 10, CGRectGetWidth(self.startCityTF.frame), CGRectGetHeight(self.startCityTF.frame))];
    self.endCityTF.text = @"目的城市";
    [self.view addSubview:self.endCityTF];
    // 目的地址
    self.endAddressTF = [[UITextField alloc] initWithFrame:CGRectMake(CGRectGetMaxX(self.endCityTF.frame) + 30, CGRectGetMinY(self.endCityTF.frame), CGRectGetWidth(self.endCityTF.frame), CGRectGetHeight(self.endCityTF.frame))];
    self.endAddressTF.text = @"目的地址";
    [self.view addSubview:self.endAddressTF];;
    
    // 添加线路规划按钮
    UIButton *roadButton = [UIButton buttonWithType:UIButtonTypeCustom];
    roadButton.frame = CGRectMake(CGRectGetMaxX(self.startAddressTF.frame) + 10, CGRectGetMaxY(self.startAddressTF.frame), 100, 30);
    [roadButton setTitle:@"线路规划" forState:UIControlStateNormal];
    [roadButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    // 设置点击方法
    [roadButton addTarget:self action:@selector(roadAction:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:roadButton];

    // 添加地图
    self.mapView = [[BMKMapView alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(self.endAddressTF.frame) + 5, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height - CGRectGetMaxY(self.endAddressTF.frame) - 5)];
    // 设置代理
    self.mapView.delegate = self;
    [self.view addSubview:self.mapView];
 
   
}

// 开始定位方法
- (void)leftAction:(UIBarButtonItem *)leftButton
{
    // 开启定位服务
    [self.locationService startUserLocationService];
    // 在地图上显示用户位置
    self.mapView.showsUserLocation = YES;
    
}
// 关闭定位方法
- (void)rightAction:(UIBarButtonItem *)rightButton
{
    // 关闭定位服务
    [self.locationService stopUserLocationService];
    // 设置地图不显示用户位置
    self.mapView.showsUserLocation = NO;
    // 删除我们添加的标注对象
    [self.mapView removeAnnotation:self.mapView.annotations.lastObject];
}
// 线路规划点击方法
- (void)roadAction:(UIButton *)button
{
    // 完成正向地理编码
    // 1、创建正向地理编码选项对象
    BMKGeoCodeSearchOption *geocoderOption = [[BMKGeoCodeSearchOption alloc] init];
    // 2、给进行正向地理位置编码的位置赋值
    geocoderOption.city = self.startCityTF.text;
    geocoderOption.address = self.startAddressTF.text;
    // 执行地理位置编码
    [self.geocoder geoCode:geocoderOption];
    
    
}
#pragma mark - BMKLocationService代理方法
-(void)willStartLocatingUser
{
    NSLog(@"开始定位");
}
-(void)didFailToLocateUserWithError:(NSError *)error
{
    NSLog(@"定位失败%@", error);
}

/**
 *  定位成功,再次定位的方法(定位成功触发)
 */
-(void)didUpdateBMKUserLocation:(BMKUserLocation *)userLocation
{
    // 完成地理反编码
    // 1、创建反向地理编码选项对象
    BMKReverseGeoCodeOption *reverseOption = [[BMKReverseGeoCodeOption alloc] init];
    // 2、给反向地理编码选项对象坐标点赋值
    reverseOption.reverseGeoPoint = userLocation.location.coordinate;
    // 3、执行反向地理编码操作
    [self.geocoder reverseGeoCode:reverseOption];
    
}

#pragma mark - BMKGeoCodeSearch代理方法

//反编码代理方法执行
-(void)onGetReverseGeoCodeResult:(BMKGeoCodeSearch *)searcher result:(BMKReverseGeoCodeResult *)result errorCode:(BMKSearchErrorCode)error
{
    // 定义大头针标注
    BMKPointAnnotation *annotation = [[BMKPointAnnotation alloc] init];
    // 设置标注位置坐标
    annotation.coordinate = result.location;
    annotation.title = result.address;
    annotation.subtitle = [NSString stringWithFormat:@"%f-%f", result.location.latitude, result.location.longitude];
    // 添加到地图里
    [self.mapView addAnnotation:annotation];
    // 使地图显示该位置
    [self.mapView setCenterCoordinate:result.location animated:YES];
}
// 正向编码代理方法
-(void)onGetGeoCodeResult:(BMKGeoCodeSearch *)searcher result:(BMKGeoCodeResult *)result errorCode:(BMKSearchErrorCode)error
{
    //
    if ([result.address isEqualToString:self.startAddressTF.text]) {
        // 当前编码的对象是开始节点
        self.statNode = [[BMKPlanNode alloc] init];
        //给节点的坐标位置赋值
        _statNode.pt = result.location;
        // 发起对目标节点的地理编码
        // 1、创建正向地理编码选项对象
        BMKGeoCodeSearchOption *geoOption = [[BMKGeoCodeSearchOption alloc] init];
        geoOption.city = self.endCityTF.text;
        geoOption.address = self.endAddressTF.text;
        // 执行编码
        [self.geocoder geoCode:geoOption];
        
         self.endNode = nil;
    } else {
        
        self.endNode = [[BMKPlanNode alloc] init];
        _endNode.pt = result.location;
    }
    if (_statNode != nil && _endNode != nil) {
        
        // 开始执行路线规划
        
        //1、创建驾车路线规划 这里以自驾模式为例 还可以是公交路线或者步行路线规划
        BMKDrivingRoutePlanOption *drivingRouteOption = [[BMKDrivingRoutePlanOption alloc] init];
        // 2、指定开始节点和目标节点
        drivingRouteOption.from = _statNode;
        drivingRouteOption.to = _endNode;
        // 3、让路线搜索服务对象搜索路线 开始执行代理方法
        [self.routeSearch drivingSearch:drivingRouteOption];
        
    }
    
}
// 获取到自驾路线回调
- (void)onGetDrivingRouteResult:(BMKRouteSearch *)searcher result:(BMKDrivingRouteResult *)result errorCode:(BMKSearchErrorCode)error
{
    // 删除原来的覆盖物
    NSArray *array = [NSArray arrayWithArray:self.mapView.annotations];
    [self.mapView removeAnnotations:array];
    // 删除overlays(原来的痕迹)
    array = [NSArray arrayWithArray:self.mapView.overlays];
    [self.mapView removeOverlays:array];
    //
    if (error == BMK_SEARCH_NO_ERROR) {
        // 选取获取到所有路线中的一条路线
        BMKDrivingRouteLine *plan = [result.routes objectAtIndex:0];
        // 计算路线方案中路段的数目
        NSUInteger size = [plan.steps count];
        // 声明一个整型变量用来计算所有轨迹点的总数
        int planPointCounts = 0;
        for (int i = 0; i < size; i++) {
            // 获取路线中的路段
            BMKDrivingStep *step = plan.steps[i];
            if (i == 0) {
                // 地图显示经纬区域
                [self.mapView setRegion:BMKCoordinateRegionMake(step.entrace.location, BMKCoordinateSpanMake(0.001, 0.001))];
            }
            
            // 累计轨迹点
            planPointCounts += step.pointsCount;
        }
        
        // 声明一个结构体数组来保存所有的轨迹点(每一个轨迹点都是一个结构体)
        // 轨迹点结构体的名字为BMKMapPoint C++写法,必须写在.mm文件中
        BMKMapPoint *tempPoints = new BMKMapPoint[planPointCounts]; // 声明一个有planPointCounts个元素的数组,数组名为tempPoints
        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++) {
                // 获取每个轨迹点的x y放入数组中
                tempPoints[i].x = transitStep.points[k].x;
                tempPoints[i].y = transitStep.points[k].y;
                i++;
                
            }
        }
        
        // 通过轨迹点构造BMKPolyline(折线)
        BMKPolyline *polyline = [BMKPolyline polylineWithPoints:tempPoints count:planPointCounts];
        // 添加到mapView上
        // 想要在地图上显示轨迹 只能先添加overlay对象(类似大头针标注)添加好之后,地图就会根据设置的overlay显示出轨迹
        [self.mapView addOverlay:polyline];
    }
}

#pragma mark - mapView代理方法
-(BMKOverlayView *)mapView:(BMKMapView *)mapView viewForOverlay:(id<BMKOverlay>)overlay
{
    if ([overlay isKindOfClass:[BMKPolyline class]]) {
        
        // 创建要显示的折线
        BMKPolylineView *view = [[BMKPolylineView alloc] initWithOverlay:overlay];
        // 设置该线条的填充颜色
        view.fillColor = [UIColor redColor];
        // 设置线条颜色
        view.strokeColor = [UIColor redColor];
        // 设置线条宽度
        view.lineWidth = 3;
        return view;
    }
    
    return nil;
}

@end


注:静态库中采用ObjectC++实现,因此需要您保证您工程中至少有一个.mm后缀的源文件(您可以将任意一个.m后缀的文件改名为.mm)。

代码中包含C++语法因此必须写在.mm文件中。例如BMKMapPoint *tempPoints = new BMKMapPoint[planPointCounts];,因此上面代码一定要写在.mm文件中。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值