第一次使用百度地图,在iOS上。上一次使用百度地图是在一个多月前,因为那时刚好百度地图更新了SDK,之前也没有这么研究过百度地图,所以这个项目的Android版本使用的百度地图SDK不是最新的。
先上效果图:
但这次,iOS版本开发使用的是v2.3.0 版本,目前最新的百度地图SDK,当然,也遇到了不少问题。知道现在,才勉强解决好了自己需要的那些功能。
这次,就记录下来,作为分享,当然,也是为了方便自己以后的开发使用。
1.首先,进百度地图<iOS SDK>界面:http://developer.baidu.com/map/sdk-ios.htm,页面上有获取密钥这栏(如果,还没有百度账号的,要先注册账号),申请一个密钥,需要自己项目的Bundle Identifier(开发过Android的读者应该知道,这个类似于Manifest中的包签名)。这一步也不是很重要,从百度地图官网都可以得到:http://developer.baidu.com/map/sdkiosdev-1.htm#.E7.AE.80.E4.BB.8B3。所以不做过多接受了。
2.下载SDK v2.3.0,这个进入第一个链接的相关下载即可下载得到。得到的文件中包含了百度地图demo/sdk/doc等,即
这三个文件分别是参考文档/库函数/官方例子。当然,我们工程中需要的是Lib.zip,当然,不论是谁,都应该去看看百度提供的Sample以及他的参考文档,这样,才能拥有不同的收获。
3.将类库以及静态库拉入项目中,我的项目是这样:,其中BaiduMapSDK是自己建立的一个分组,mapapi.bundle是存放地图的一些资源,libbaidumapapi.a是静态库,inc是一些类库头文件。这三者都是必须的。当然,这里关于静态库需要说一下。因为下载的SDK中有两个静态库,不同的区别。一个试用与真机,一个试用于虚拟机。这些在官网中说的也非常详细了,所以,处理静态文件可以按照官网提供的方式:http://developer.baidu.com/map/wiki/index.php?title=iossdk/guide/hellobaidumap 参考 引入静态库文件,(个人建议使用第三种方式,静态库的合成:http://www.myexception.cn/mobile/1683246.html<如果百度官网中还没有研究透彻,那么就看这个简单的合成>) 然后就是各种引入系统Framework,这个导入同样参考这个网址中的数据。
4.特别注明,这期间不用修改任何系统文件/属性。只需要按照步骤一步一步来就可。小编就是听从朋友的建议,改了又改,造成了很多的误解。切记呀。
5.开始研发:小编采用的是StoryBoard布局,布局如下:
当然,这里的父视图是一个View,然后添加了一个View子视图,用来替换导航栏。当然了,这是用来显示地图的,所以,全屏设置了一个BMKMapView,由于这里是空白,显示出来就看不见了。这样设置了,添加一个全屏UIView,修改他的父类为BMKMapView,当然,也可以在代码中实现这些。不过,这些都不是重点。绑定对应的控件就不作出阐述了。
6.布局完成了,就该来实现代码了。找到AppDelegate.h
@interface AppDelegate : UIResponder <UIApplicationDelegate>
{
UIWindow *windows;
UINavigationController *navigationController;
BMKMapManager* _mapManager;
}
6.1 继续完成在AppDelegate.m的配置
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// 要使用百度地图,请先启动BaiduMapManager
_mapManager = [[BMKMapManager alloc]init];
// 如果要关注网络及授权验证事件,请设定 generalDelegate参数
BOOL ret = [_mapManager start:@"ugr9Z0DoKlalwgjRDmHGi4MY" generalDelegate:nil];
if (!ret) {
NSLog(@"manager start failed!");
}
// Add the navigation controller's view to the window and display.
[windows addSubview:navigationController.view];
[windows makeKeyAndVisible];
return YES;
}
不过记得在.h 文件中导入
#import "BMKMapManager.h"
7.回到定义的显示地图的ViewController中,将其.m文件修改为.mm文件,这个在百度官网中解释为:注:静态库中采用ObjectC++实现,因此需要您保证您工程中至少有一个.mm后缀的源文件(您可以将任意一个.m后缀的文件改名为.mm)
7.1 开始初始化地图控件,设置相关属性
- (void)viewDidLoad
{
[super viewDidLoad];
[self initMapView];
}
//初始化MapView
-(void)initMapView{
//地图类型为普通类型
_mapView.mapType=BMKMapTypeStandard;
//地图缩放级别
_mapView.zoomLevel=16;
}
关于显示地图,还需要设置
#pragma mark 地图将要出现
-(void)viewWillAppear:(BOOL)animated
{
[_mapView viewWillAppear];
self.navigationController.navigationBarHidden = YES;
_mapView.delegate = self; // 此处记得不用的时候需要置nil,否则影响内存的释放
_locationService.delegate = self;//这是定位服务
}
#pragma mark 地图将要消失
-(void)viewWillDisappear:(BOOL)animated {
[_mapView viewWillDisappear];
_mapView.delegate = nil; // 不用时,置nil
_locationService.delegate = nil;
_searcher.delegate=nil;//这是进行关键词搜索
}
这里一起将之后需要用到的定位服务,关键词搜索等委托一起复制了出来,无怪,这里给出MapView的一些协议方法,如果需要做出什么操作,根据自己需要处理。
#pragma mark 地图zoomlevel++
-(void)zoomMap:(id)sender
{
_mapView.zoomLevel = _mapView.zoomLevel++;
}
#pragma mark 地图ZoomLevel--
-(void)subMap:(id)sender
{
_mapView.zoomLevel = _mapView.zoomLevel--;
}
//上边是放大缩小
#pragma mark 地图长按事件
-(void)mapview:(BMKMapView *)mapView onLongClick:(CLLocationCoordinate2D)coordinate
{
}
#pragma mark 地图双击手势
- (void)mapview:(BMKMapView *)mapView onDoubleClick:(CLLocationCoordinate2D)coordinate
{
}
// 当前地图类型,可设定为标准地图、实时路况、卫星地图、同时打开实时路况和卫星地图模式
@property (nonatomic) BMKMapType mapType;
enum {
BMKMapTypeStandard = 1, ///< 标准地图
BMKMapTypeTrafficOn = 2, ///< 实时路况
BMKMapTypeSatellite = 4, ///< 卫星地图
BMKMapTypeTrafficAndSatellite = 8, ///< 同时打开实时路况和卫星地图
};
typedef NSUInteger BMKMapType;
源码中给出了这几个类型,敢兴趣的可以尝试一下。
7.2 关于使用百度地图进行定位
//初始化定位设置
- (void)initLocation{
//定位服务
_locationService = [[BMKLocationService alloc]init];
[_locationService startUserLocationService];//开始定位
_mapView.showsUserLocation = NO;//不显示定位图层
_mapView.userTrackingMode = BMKUserTrackingModeFollow;//设置定位模式为定位跟随,这里提供了三者模式,小编就不一一介绍了
_mapView.showsUserLocation = YES;//设置为显示
}
定位之后,相关的处理方法都需要在其协议方法中实现,故此推出以下方法:
#pragma mark 在开时定位时调用
- (void)willStartLocatingUser
{
}
#pragma mark 在停止定位后,会调用此函数
- (void)didStopLocatingUser
{
}
#pragma mark 在地图View将要启动定位时,会调用此函数
- (void)mapViewWillStartLocatingUser:(BMKMapView *)mapView
{
}
#pragma mark 用户位置更新后,会调用此函数
- (void)didUpdateUserLocation:(BMKUserLocation *)userLocation
{
[_mapView updateLocationData:userLocation];
//物理地址
BMKGeoCodeSearch *search = [[BMKGeoCodeSearch alloc]init];
search.delegate=self;
//进行反地理位置编码
BMKReverseGeoCodeOption *rever = [[BMKReverseGeoCodeOption alloc]init];
rever.reverseGeoPoint = userLocation.location.coordinate;
[search reverseGeoCode:rever];
//停止定位
[_locationService stopUserLocationService];
}
#pragma mark 在地图View停止定位后,会调用此函数
- (void)mapViewDidStopLocatingUser:(BMKMapView *)mapView
{
}
#pragma mark 定位失败后,会调用此函数
- (void)mapView:(BMKMapView *)mapView didFailToLocateUserWithError:(NSError *)error
{
}
这里提到了反地理编码,原因是定位的时候只得到了经纬度,本次通过经纬度来进行反地理编码,得到详细地址,这里的反地理编码实现了代理,所以结果在代码方法中处理:
#pragma mark 获取到物理地址信息
-(void)onGetReverseGeoCodeResult:(BMKGeoCodeSearch *)searcher result:(BMKReverseGeoCodeResult *)result errorCode:(BMKSearchErrorCode)error
{
//得到当前详细地址和城市
_address=result.address;
_city=result.addressDetail.city;
//设置显示的值
[_addressTextField setText:_address];
}
上面是两个属性和一个控件,主要是得到城市和地址以及显示地址信息,
BMKReverseGeoCodeResult 这个类是得到的地址信息,其属性四个,可以点击进库函数查看,这里就不做详细介绍了。
8.关于重新定位:就是自己手动再调用一次定位函数
- (IBAction)setLocationButton:(id)sender {
[self initLocation];
}<span style="color:#ffffff;">
</span>
//这里进行地址搜索
- (void)sureButton{
NSLog(@"确定");
//初始化检索对象
_searcher =[[BMKSuggestionSearch alloc]init];
_searcher.delegate = self;
BMKSuggestionSearchOption* option = [[BMKSuggestionSearchOption alloc] init];//初始化搜索设置参数对象
option.cityname = cityText.text;//设置搜索城市
option.keyword = addressText.text;//设置关键词
BOOL flag = [_searcher suggestionSearch:option];
if(flag)
{
NSLog(@"建议检索发送成功");
}
else
{
NSLog(@"建议检索发送失败");
}
}
关于cityText/addressText是小编定义的两个UITextField,而SureButton是按钮的点击事件。效果图如下:
这是小编自定义的UIAlertDialog,没有什么技术含量,就不解释了。继续地图
点击按钮后,就进行了关键词搜索,搜索出来的,全是地理位置信息,这个就有点不好弄了,因为小编要把搜索出来的地址显示到界面,所以就采用了地理编码。详情如下
//实现Delegate处理回调结果
- (void)onGetSuggestionResult:(BMKSuggestionSearch*)searcher result:(BMKSuggestionResult*)result errorCode:(BMKSearchErrorCode)error{
if (error == BMK_SEARCH_NO_ERROR) {
//在此处理正常结果
NSLog(@"找到%@--%@---%@",result.districtList,result.cityList,result.keyList);
[addressText setText:[result.districtList objectAtIndex:2]];
NSString *citys=@"";
NSString *addresses=@"";
for (int i=1; i<[result.districtList count]; i++) {
//初始化检索对象
_geoCodeSearch =[[BMKGeoCodeSearch alloc]init];//必须将BMKGeoCodeSearch的创建放在这里面,因为不用他的时候,他自动销毁了。内容也会覆盖。如果放在外面创建,那么地理编码永远都只会得到最后一个
//实现委托
_geoCodeSearch.delegate = self;
//设置城市
citys=[result.cityList objectAtIndex:i];
//设置详细地址信息
addresses=[NSString stringWithFormat:@"%@%@",[result.districtList objectAtIndex:i],[result.keyList objectAtIndex:i]];
//创建地理编码的Option对象
BMKGeoCodeSearchOption *geoCodeSearchOption = [[BMKGeoCodeSearchOption alloc]init];
//设置地理编码参数
geoCodeSearchOption.city= citys;
geoCodeSearchOption.address = addresses;
//获取是否成功
BOOL flag = [_geoCodeSearch geoCode:geoCodeSearchOption];
if(flag)
{
NSLog(@"geo检索发送成功");
}
else
{
NSLog(@"geo检索发送失败");
}
}
}
else {
NSLog(@"抱歉,未找到结果");
}
}
当然了,还有一些属性,小编采用系统默认的,也就不设置了,如果读者有需要,可以自行设置。这里进行了正向地理编码,也设置了委托。同上反向地理编码,实现委托协议
//接收正向编码结果
- (void)onGetGeoCodeResult:(BMKGeoCodeSearch *)searcher result:(BMKGeoCodeResult *)result errorCode:(BMKSearchErrorCode)error{
if (error == BMK_SEARCH_NO_ERROR) {
//在此处理正常结果
/*if (annotations != nil) {
[_mapView removeAnnotation:annotations];
}*/
// 添加一个PointAnnotation
annotations = [[BMKPointAnnotation alloc]init];
//设置当前地理编码位置:CLLocationCoordinate2D ===result.location
annotations.coordinate = result.location;
//设置点击弹出POP的显示title
annotations.title = result.address;
//添加图标
[_mapView addAnnotation:annotations];
//通过ragion设置图标显示居中
BMKCoordinateRegion region;
region.center.latitude=result.location.latitude;
region.center.longitude=result.location.longitude;
_mapView.region=region;
}
else {
NSLog(@"抱歉,未找到结果");
}
}
小编这里将产生出来的位置进行了地图绘制《大头针》,当然也设置了大头针所在位置为居中,这个想必大家都明白,也实现了大头针点击的弹出pop,上面注释的代码 是移除大头针的。因为这里是多个图标,所以就没有移除,不过,根据读者需要自行设置。
然后就是弹出的POP了和绘制大头针,继续实现协议方法
//这是绘制大头针
- (BMKAnnotationView *)mapView:(BMKMapView *)mapView viewForAnnotation:(id <BMKAnnotation>)annotation
{
if ([annotation isKindOfClass:[BMKPointAnnotation class]]) {
BMKPinAnnotationView *newAnnotationView = [[BMKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"myAnnotation"];
[newAnnotationView setImage:[UIImage imageNamed:@"btn_back_action_bar"]];
newAnnotationView.pinColor = BMKPinAnnotationColorRed;//设置大头针颜色
newAnnotationView.animatesDrop = NO;// 取消该标记点动画显示
return newAnnotationView;
}
return nil;
}
到这里,基本上就结束了,当然,提供上.h 文件中的代码
#import <UIKit/UIKit.h>
#import "BMapKit.h"
@interface MapLocationViewController : UIViewController<BMKMapViewDelegate,BMKLocationServiceDelegate,BMKSuggestionSearchDelegate,BMKGeoCodeSearchDelegate,UITextFieldDelegate>{
BMKSuggestionSearch *_searcher;
BMKGeoCodeSearch *_geoCodeSearch;
}
@property(nonatomic,strong)BMKLocationService *locationService;
- (IBAction)saveButton:(id)sender;
- (IBAction)backButton:(id)sender;
@property (weak, nonatomic) IBOutlet UITextField *addressTextField;
@property (weak, nonatomic) IBOutlet BMKMapView *mapView;
- (IBAction)setLocationButton:(id)sender;
- (IBAction)searcheButton:(id)sender;
@property(nonatomic,strong)NSString *city;
@property(nonatomic,strong)NSString *address;
@end
没有注释,见谅,嘻嘻,主要是实现了各种协议,这个在实现协议的时候,可以点击进去看看,到底是什么协议。小编这里就不解释了。不好意思,因为百度地图的库函数写的都特别详细,注释都特别到位。
当然了,小编乃小白一枚,走过路过的大牛们,有指导的希望能够指导指导,想喷的尽全力喷。小编将不胜感激。在磨砺中,咱们共同成长!谢谢!