项目最近对地图整体模块进行了重构, 为了和我们的安卓同学保持统一,放弃了原本就很6的高德地图,全部改用百度地图(虽然我觉得百度地图不好用,文档也一般,但是没办法啊,没办法啊 啊啊啊啊啊..).
项目中用到的百度地图的主要功能点有以下几个:
- 基础地图和定位
- 反地理编码功能
- poi检索
- 搜索建议和poi详情检索
- 区域检索功能
- 通过url调起第三方地图进行
- 自定义弹出泡泡
在实际的使用过程中这些功能可能会有交叉,所以代码会整个贴过来,下面就根据实际功能需求一一介绍.
一.基础地图和定位功能
地图的初始化:
- (void)initMapView {
self.mapView = [[BMKMapView alloc] initWithFrame:CGRectMake(0, 44, SCREEN_WIDTH, SCREEN_WIDTH/372*253)];
self.mapView.showsUserLocation = YES;
self.mapView.userTrackingMode = BMKUserTrackingModeNone;
self.mapView.gesturesEnabled = YES;
self.mapView.zoomEnabled = YES;
self.mapView.maxZoomLevel = 23;
self.mapView.zoomLevel = 16;
// 显示比例尺 200m (和微信一样....)
self.mapView.showMapScaleBar = YES;
// 回到当前位置按钮
UIButton *showUserLocation = [[UIButton alloc] initWithFrame:CGRectMake(self.mapView.mj_width - 21 - 50, self.mapView.mj_height - 21 - 50, 50, 50)];
[self.mapView addSubview:showUserLocation];
[showUserLocation addTarget:self action:@selector(backToCurrentLocation) forControlEvents:UIControlEventTouchUpInside];
[showUserLocation setBackgroundImage:[UIImage imageNamed:@"showuserlocation"] forState:UIControlStateNormal];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(self.mapView.mj_width * 0.5 - 8, self.mapView.mj_height * 0.5 - 40, 16, 40)];
imageView.image = [UIImage imageNamed:@"datouzhen"];
imageView.contentMode = UIViewContentModeScaleAspectFit;
[self.mapView addSubview:imageView];
[self.view addSubview:self.mapView];
}
这里提醒一点百度地图各项服务的delegate需要在 viewWillApper设置为self,viewWillDisapper时设置为nil,否则的话会出现内存泄露.
以下是定位成功后的回调方法
/**
*用户位置更新后,会调用此函数
*@param userLocation 新的用户位置
*/
- (void)didUpdateBMKUserLocation:(BMKUserLocation *)userLocation
{
[self.mapView updateLocationData:userLocation];
CLLocation *location = userLocation.location;
// 如果不是区域检索
if (!(self.city.length > 0)) {
// 设置当前位置为地图的中心点
NSLog(@"%f-----%f",userLocation.location.coordinate.latitude,userLocation.location.coordinate.longitude);
[self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude) animated:YES];
}
self.currentCoor = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude);
// 定位成功会后
if (location) {
[self.locationService stopUserLocationService];
// 反向编码
[self beginReverseGeoCodeSearch];
}
}
这里进行了判断,如果不是区域检索(如果我人在北京,但是要让地图显示是石家庄市 此时需要用到区域检索),则将当前定位到的位置设置为地图的中心点 . 然后开始进行反地理编码.
二.反地理编码
因为在发布分享的时候有一个选项显示的是当前所在的城市,如下图一,二 . 第二个cell显示的 "北京市" 所以需要进行反地理编码.
反地理编码成功后的回调:
// 反地理编码回调
- (void)onGetReverseGeoCodeResult:(BMKGeoCodeSearch *)searcher result:(BMKReverseGeoCodeResult *)result errorCode:(BMKSearchErrorCode)error {
// result ->poiList ///地址周边POI信息,成员类型为BMKPoiInfo
// @property (nonatomic, strong) NSArray* poiList;
if (result.poiList.count > 0) {
self.currentPoiInfo = [result.poiList firstObject];
}
// 反向地理编码成功后 ,进行poi搜索
[self beginPoiSearch:self.currentCoor keyword:@""];
}
三.poi 检索
百度地图poi只能设置一个关键字(也有可能是我没找到方法,如果可以设置多个请及时联系,谢谢)
发起poi检索
#pragma mark ----发起检索
// 发起poi检索
- (void)beginPoiSearch:(CLLocationCoordinate2D)coor keyword:(NSString *)keyowrd{
BMKNearbySearchOption *option = [[BMKNearbySearchOption alloc]init];
option.pageCapacity = 50;
// 按距离排序
option.sortType = BMK_POI_SORT_BY_DISTANCE;
// 以地图中心点为坐标发起检索 默认keyword 写字楼
option.location = CLLocationCoordinate2DMake(coor.latitude, coor.longitude);
option.keyword = keyowrd.length > 0 ? keyowrd : @"写字楼";
BOOL flag = [self.poiSearch poiSearchNearBy:option];
NSLog(@"%@",flag ? @"周边检索发送成功" : @"周边检索发送失败");
}
poi检索发起成功后的页面展示如下图:
图 一 图 二
这里除了poi检索之外,还加了一个地图中心点功能,及拖动地图的时候以大头针的位置为当前地图的中心点,然后再进行poi检索.这里需要监听另外一个回调方法.
// 拖拽地图的回调
- (void)mapView:(BMKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
[self beginPoiSearch:self.mapView.centerCoordinate keyword:self.keyword.length > 0 ? self.keyword : @""];
}
在这个回调方法中,以当前地图的中心为poi检索的中心点 发起poi检索.
四.搜索建议功能和poi详情检索
搜搜建议功能截图如下图:
在serchDisplayController的代理方法中发送搜索建议的请求:
#pragma mark ---displayControllerDelegate
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller
shouldReloadTableForSearchString:(NSString *)searchString {
self.searchText = searchString;
self.suggestSearch = [[BMKSuggestionSearch alloc]init];
self.suggestSearch.delegate = self;
BMKSuggestionSearchOption* option = [[BMKSuggestionSearchOption alloc] init];
option.cityname = self.city;
option.keyword = searchString;
BOOL flag = [self.suggestSearch suggestionSearch:option];
NSLog(@"%@",flag ? @"建议检索发送成功" : @"建议检索发送失败");
return YES;
}
然后在其回调方法中处理搜索建议结果:
// 搜索建议返回的关键词list和区list ,coor list,poi id list
@property (nonatomic,strong)NSMutableArray *keyList; // 万达广场
@property (nonatomic,strong)NSMutableArray *districtList; // 海淀区
@property (nonatomic,strong)NSMutableArray *coorList; // coor 包装成的 NSValue对象
@property (nonatomic,strong)NSMutableArray *poiuIdList; // poi id
- (void)onGetSuggestionResult:(BMKSuggestionSearch *)searcher
result:(BMKSuggestionResult *)result
errorCode:(BMKSearchErrorCode)error {
self.keyList = [NSMutableArray arrayWithCapacity:0];
self.districtList = [NSMutableArray arrayWithCapacity:0];
self.coorList = [NSMutableArray arrayWithCapacity:0];
self.poiuIdList = [NSMutableArray arrayWithCapacity:0];
NSMutableArray *emptyLocationArray = [NSMutableArray arrayWithCapacity:0];
for (int i = 0; i<result.ptList.count; i++) {
CLLocationCoordinate2D coor;
NSValue *coorValue = result.ptList[i];
[coorValue getValue:&coor];
// 非空的地址加到数组中
if (!((int)coor.latitude == 0 && (int)coor.longitude == 0)) {
[emptyLocationArray addObject:[NSString stringWithFormat:@"%d",i]];
[self.keyList addObject:result.keyList[i]];
[self.districtList addObject:result.districtList[i]];
[self.coorList addObject:result.ptList[i]];
[self.poiuIdList addObject:result.poiIdList[i]];
}
}
[self.displayController.searchResultsTableView reloadData];
}
点击搜索建议tableView的cell时,需要mapView跳转到对应的位置,并搜索其附近对应的poi信息(比如我点的结果是个餐厅,那么就地图就滚动到这个餐厅的位置,并以"餐饮"为关键词搜索附近的poi信息),所以这里需要用到另外一个接口:poi详情搜索(注意是poi详情搜索,两个有点像)
点击cell时,根据poi 的id发起poi详情搜索 :
// 发起poi 详情检索
- (void)beginPoiDetailSearch:(NSString *)uid {
BMKPoiDetailSearchOption* option = [[BMKPoiDetailSearchOption alloc] init];
option.poiUid = uid;//POI搜索结果中获取的uid
BOOL flag = [self.poiSearch poiDetailSearch:option];
NSLog(@"%@",flag ? @"POI详情检索发送成功" : @"POI详情检索发送失败");
}
poi详情检索成功后的回调:
- (void)onGetPoiDetailResult:(BMKPoiSearch *)searcher result:(BMKPoiDetailResult *)poiDetailResult errorCode:(BMKSearchErrorCode)errorCode {
CLLocationCoordinate2D coor;
NSValue *coorValue = self.coorList[self.searchResultSelectedIndexPath.row];
[coorValue getValue:&coor];
self.keyword = poiDetailResult.tag;
// 改变中心坐标
[self.mapView setCenterCoordinate:coor animated:YES];
[self beginPoiSearch:coor keyword:poiDetailResult.tag];
}
返回的结果是 BMKPoiDetailResult 对象,里面包含了 poi的详细信息,包括 name address tag(poi标签)等.
然后以 poiDetailResult.tag 为关键字进行poi搜索.
五.区域检索功能
我人在北京,但是想查看石家庄的景点,小吃等信息 . 此时就需要用到区域检索功能了. 先判断
if (self.city.length > 0) {
[self beginDistrictSearch];
} 如果传过来的城市的名字长度大于 0 则说明要先进行区域检索.
// 发起区域检索
- (void)beginDistrictSearch {
//初始化检索对象
self.districtSearch = [[BMKDistrictSearch alloc] init];
//设置delegate,用于接收检索结果
self.districtSearch.delegate = self;
//构造行政区域检索信息类
BMKDistrictSearchOption *option = [[BMKDistrictSearchOption alloc] init];
option.city = self.city;
option.district = self.district;
//发起检索
BOOL flag = [self.districtSearch districtSearch:option];
NSLog(@"%@",flag ? @"区域检索发送成功" : @"区域检索发送失败");
}
区域检索成功后的回调:
- (void)onGetDistrictResult:(BMKDistrictSearch *)searcher result:(BMKDistrictResult *)result errorCode:(BMKSearchErrorCode)error {
NSLog(@"---->%f----%f",result.center.latitude,result.center.longitude);
// 设置地图中心点
[self.mapView setCenterCoordinate:result.center animated:YES];
// 以城市中心点为中心发起poi检索
[self beginPoiSearch:result.center keyword:@""];
}
这样就可以实现检索不同省份城市的 poi信息了.
六.通过url调起第三方地图进行
效果如下图:
点击上面导航按钮会进行判断,判断当前app是否安装了高德,百度以及苹果自带的地图 如果有则将其展示出来否则则不显示. 点击之后则会调起对应的地图进行导航,具体实现可以看我这篇博客 iOS通过URL调起第三方地图进行导航
七.自定义弹出pop
效果如下图:
点击大头针弹出pop ,这里的pop是自己绘制的代码:
@interface BubbleView : UIView
@end
@implementation BubbleView
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
CGFloat width = rect.size.width;
CGFloat height = rect.size.height;
CGFloat radius = 5;
CGFloat jianjiaoH = 12;
// 获取CGContext,注意UIKit里用的是一个专门的函数
CGContextRef context = UIGraphicsGetCurrentContext();
// 移动到初始点
CGContextMoveToPoint(context, radius, 0);
// 绘制第1条线和第1个1/4圆弧
CGContextAddLineToPoint(context, width - radius, 0);
CGContextAddArc(context, width - radius, radius, radius, -0.5 * M_PI, 0.0, 0);
// CGContextAddArc(<#CGContextRef _Nullable c#>, <#CGFloat x#>, <#CGFloat y#>, <#CGFloat radius#>, <#CGFloat startAngle#>, <#CGFloat endAngle#>, <#int clockwise#>)
// 绘制第2条线和第2个1/4圆弧 17
CGContextAddLineToPoint(context, width, height - radius - jianjiaoH);
CGContextAddArc(context, width - radius, height - radius - jianjiaoH, radius, 0.0, 0.5 * M_PI, 0);
// 绘制第3条线和第3个1/4圆弧和尖角
CGContextAddLineToPoint(context, width/2 + 9, height - jianjiaoH);
CGContextAddLineToPoint(context, width/2, height);
CGContextAddLineToPoint(context, width/2 - 9, height - jianjiaoH);
CGContextAddLineToPoint(context, width - radius, height - jianjiaoH);
CGContextAddArc(context, radius, height - radius - jianjiaoH, radius, 0.5 * M_PI, M_PI, 0);
// 绘制第4条线和第4个1/4圆弧
CGContextAddLineToPoint(context, 0, radius);
CGContextAddArc(context, radius, radius, radius, M_PI, 1.5 * M_PI, 0);
// 闭合路径
CGContextClosePath(context);
// 填充半透明黑色
CGContextSetRGBFillColor(context, 0, 0, 0.0, 0.5);
CGContextDrawPath(context, kCGPathFill);
}
@end
至此,此次我们用的百度地图的功能已经全部分享给大家了,如果纰漏请指正 .全部的代码我贴在动弹里了 -_-
来源:oschina
链接:https://my.oschina.net/u/2604520/blog/748468