最近项目中使用到了百度地图,用地图查找房源,并显示指定区域内房源数量,项目完成后码出来梳理记录一下。
关于定位
iOS 系统不允许使用第三方定位,所以地图SDK中的定位方法其实际上还是对原生定位的二次封装,以便开发者方便使用。
当然如果需要可以选择将定位功能封装成一个单例。
//初始化BMKLocationService
_locService = [[BMKLocationService alloc]init];
_locService.delegate = self;
//启动LocationService
[_locService startUserLocationService];
//实现相关delegate 处理位置信息更新
//处理方向变更信息
- (void)didUpdateUserHeading:(BMKUserLocation *)userLocation{
//NSLog(@"heading is %@",userLocation.heading);
}
//处理位置坐标更新
- (void)didUpdateBMKUserLocation:(BMKUserLocation *)userLocation {
//NSLog(@"didUpdateUserLocation lat %f,long %f",userLocation.location.coordinate.latitude,userLocation.location.coordinate.longitude);
}
//以下_mapView为BMKMapView对象
_mapView.showsUserLocation = YES;//显示定位图层
[_mapView updateLocationData:userLocation];
自定义标注
项目原先需求是要做类似于百度聚合的效果,显示每个行政区内房源数量,但聚合功能现提供的算法是根据区块距离相近时,自动聚合。所以变通的处理是,根据地图放大级别显示不同的标注。
//地图区域改变完成后会调用此接口
- (void)mapView:(BMKMapView *)mapView regionDidChangeAnimated:(BOOL)animated{
if (mapView.zoomLevel >= 13.500000) {
//取消地图上的所有区域标注,并添加详情标注
[mapView removeAnnotations:self.annotationArr];
[self addDetailAnnotation];
}else{
//取消地图上所有的详情标注,并添加区域标注
[mapView removeAnnotations:self.detailAnnotationArr];
[self addAnnotation];
}
}
- (void)addAnnotation{
[self postWithApiName: APIName
parameters:parameter
success:^(NSDictionary *resultDict) {
//请求回来后再次判断一下当前地图放大级别
//如若不然效果会较诡异
if (_mapView.zoomLevel >= 13.500000) { return ; }
//清空现有标注
[_mapView removeAnnotations:self.annotationArr];
[self.annotationArr removeAllObjects];
NSArray *arr = resultDict[@"result"];
for (NSDictionary *dic in arr) {
CLLocationCoordinate2D coor = CLLocationCoordinate2DMake([dic[@"latitude"] floatValue], [dic[@"longitude"] floatValue]);
CustomPointAnnotation *annotation=[[CustomPointAnnotation alloc]init];
annotation.coordinate = coor;
annotation.title = dic[@"area"];
annotation.subtitle = dic[@"total"];
//加载标注点
[self.annotationArr addObject:annotation];
[_mapView addAnnotation:annotation];
}
} failure:^(NSError *error) { }];
}
- (void)addDetailAnnotation{
/***得到当前地图页面左上角右下角经纬度*****/
CLLocationCoordinate2D coor1 = [_mapView convertPoint:CGPointMake(0, 0) toCoordinateFromView:_mapView ];
CLLocationCoordinate2D coor2 = [_mapView convertPoint:CGPointMake(kWidth, CGRectGetMaxY(_mapView.frame)) toCoordinateFromView:_mapView ];
[self postWithApiName:ApiName
parameters:@{@"longitude_min":@(coor1.longitude),
@"longitude_max":@(coor2.longitude),
@"latitude_min":@(coor1.latitude),
@"latitude_max":@(coor2.latitude)}
success:^(NSDictionary *resultDict) {
//请求回来后再次判断一下当前地图放大级别
//如若不然效果会较诡异
if (_mapView.zoomLevel < 13.500000) {
return ;
}
//清除详情标注
[_mapView removeAnnotations:self.detailAnnotationArr];
[self.detailAnnotationArr removeAllObjects];
//快速遍历所有房源
for (NSDictionary *dic in arr) {
//得到楼楼经纬度
CLLocationCoordinate2D coor = CLLocationCoordinate2DMake([dic[@"latitude_y"] floatValue], [dic[@"longitude_x"] floatValue]);
CustomDetailPointAnnotation *annotation=[[CustomDetailPointAnnotation alloc]init];
annotation.coordinate = coor;
annotation.title = dic[@"name"];
annotation.subtitle = dic[@"sale"];
annotation.houseID = dic[@"houseID"];
[_mapView addAnnotation:annotation];//加载标注点
[self.detailAnnotationArr addObject:annotation];
}
} failure:^(NSError *error) { }];
}
#pragma mark - 根据anntation生成对应的View
- (BMKAnnotationView *)mapView:(BMKMapView *)mapView viewForAnnotation:(id <BMKAnnotation>)annotation{
//详情标注
if ([annotation isKindOfClass:[CustomDetailPointAnnotation class]]) {
//涉及重用机制
BMKPinAnnotationView *annotationView = (BMKPinAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:@"AnnotationID"];
if (!annotationView) {
annotationView = [[BMKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"AnnotationID"];
}
annotationView.canShowCallout = NO;//不弹出汽泡
//自定义样式
UIView *bgView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 100, 45)];
UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 100, 45)];
[bgView addSubview:imageView];
UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 100, 20)];
label.font = [UIFont systemFontOfSize:12];
label.textAlignment = NSTextAlignmentCenter;
[bgView addSubview:label];
label.text = [NSString stringWithFormat:@"%@",annotation.title];
label.textColor = [UIColor blackColor];
UILabel *sublabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 15, 100, 20)];
sublabel.textColor = APP_THEME_COLOR;
sublabel.font = [UIFont systemFontOfSize:12];
sublabel.textAlignment = NSTextAlignmentCenter;
[bgView addSubview:sublabel];
sublabel.text = [NSString stringWithFormat:@"¥%@元/平",annotation.subtitle];
CustomPointAnnotation *ann = (CustomPointAnnotation*)annotation;
//选中和非选中状态下两种底图
if ([ann.houseID isEqualToString: self.flag]) {
imageView.image = [UIImage imageNamed:@"ft2"];
annotationView.selected = YES;
}else{
imageView.image = [UIImage imageNamed:@"ft1"];
annotationView.selected = NO;
}
//***根据bigView得到一张图片***//
annotationView.image = [self getImageFromView:bgView];
annotationView.annotation = annotation;
return annotationView;
}
//区域标注
if ([annotation isKindOfClass:[CustomPointAnnotation class]]) {
BMKPinAnnotationView *annotationView = (BMKPinAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:@"BigAnnotationID"];
//涉及重用
if (!annotationView) {
annotationView = [[BMKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"BigAnnotationID"];
}
annotationView.canShowCallout = NO;//不弹出汽泡
UIView *bgView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 62, 60)];
UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 62, 60)];
imageView.image = [UIImage imageNamed:@"fr"];
[bgView addSubview:imageView];
UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 62, 60)];
label.textColor = [UIColor whiteColor];
label.font = [UIFont systemFontOfSize:12];
label.textAlignment = NSTextAlignmentCenter;
label.numberOfLines = 2;
[bgView addSubview:label];
label.text = [NSString stringWithFormat:@"%@\n%@",annotation.title,annotation.subtitle];
label.textColor = [UIColor whiteColor];
annotationView.image = [self getImageFromView:bgView];
annotationView.annotation = annotation;
return annotationView;
}
//其它标注,默认就用系统的
if ([annotation isKindOfClass:[BMKPointAnnotation class]]) {
BMKPinAnnotationView *annotationView = (BMKPinAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:@"otherAnnotationID"];
if (!annotationView) {
annotationView = [[BMKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"otherAnnotationID"];
}
annotationView.animatesDrop = YES;
}
return nil;
}
- (UIImage*)getImageFromView:(UIView *)view{
CGSize s = view.bounds.size;
// 下面方法,第一个参数表示区域大小。
// 第二个参数表示是否是非透明的。
// 如果需要显示半透明效果,需要传NO,否则传YES。
// 第三个参数就是屏幕密度了
UIGraphicsBeginImageContextWithOptions(s, NO, [UIScreen mainScreen].scale);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage*image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
实现下面这两个代理方法目的是点击标注时能快速改变背景图片
#pragma mark - 选中标注视图时的方法
- (void)mapView:(BMKMapView *)mapView didSelectAnnotationView:(BMKAnnotationView *)view{
//判断是否是详情标注
if ([view.annotation isKindOfClass:[CustomDetailPointAnnotation class]]) {
view.selected = YES;
CustomDetailPointAnnotation *ann = (CustomDetailPointAnnotation*)view.annotation;
//改变点击后标注颜色,
//其实主要是改变一图底图
UIView *bgView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 100, 45)];
UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 100, 45)];
[bgView addSubview:imageView];
imageView.image = [UIImage imageNamed:@"ft2"];
UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 100, 20)];
label.font = [UIFont systemFontOfSize:12];
label.textAlignment = NSTextAlignmentCenter;
[bgView addSubview:label];
label.text = [NSString stringWithFormat:@"%@",ann.title];
label.textColor = [UIColor blackColor];
UILabel *sublabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 15, 100, 20)];
sublabel.textColor = APP_THEME_COLOR;
sublabel.font = [UIFont systemFontOfSize:12];
sublabel.textAlignment = NSTextAlignmentCenter;
[bgView addSubview:sublabel];
sublabel.text = [NSString stringWithFormat:@"¥%@元/
view.image = [self getImageFromView:bgView];
view.annotation = ann;
self.flag = ann.houseID;
[mapView setCenterCoordinate:ann.coordinate animated:YES];
}else if([view.annotation isKindOfClass:[CustomPointAnnotation class]]){
//如果点击的是区域标注则放大地图
self.flag = @"";
[mapView setZoomLevel:mapView.zoomLevel+1];
}else{
}
}
#pragma mark - 取消选中标注视图时的方法
- (void)mapView:(BMKMapView *)mapView didDeselectAnnotationView:(BMKAnnotationView *)view{
if ([view.annotation isKindOfClass:[CustomDetailPointAnnotation class]]) {
view.selected = NO;
CustomPointAnnotation *ann = (CustomPointAnnotation*)view.annotation;
//改变点击后标注颜色
UIView *bgView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 100, 45)];
UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 100, 45)];
[bgView addSubview:imageView];
imageView.image = [UIImage imageNamed:@"ft1"];
UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 100, 20)];
label.font = [UIFont systemFontOfSize:12];
label.textAlignment = NSTextAlignmentCenter;
[bgView addSubview:label];
label.text = [NSString stringWithFormat:@"%@",ann.title];
label.textColor = [UIColor blackColor];
UILabel *sublabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 15, 100, 20)];
sublabel.textColor = APP_THEME_COLOR;
sublabel.font = [UIFont systemFontOfSize:12];
sublabel.textAlignment = NSTextAlignmentCenter;
[bgView addSubview:sublabel];
sublabel.text = [NSString stringWithFormat:@"¥%@元/平",ann.subtitle];
view.image = [self getImageFromView:bgView];
view.annotation = ann;
}
}
#pragma mark - 自定义的Annotation
//区域标注
@interface CustomPointAnnotation : BMKPointAnnotation
@property (nonatomic,retain)NSString *houseID;
@end
@implementation CustomPointAnnotation
@end
//详情标注
@interface CustomDetailPointAnnotation : BMKPointAnnotation
@property (nonatomic,retain) NSString *houseID;
@property (nonatomic,retain) NSString *area;
@property (nonatomic,retain) NSString *address;
@end
@implementation CustomDetailPointAnnotation
@end
PS:
在项目功能实现时遇到的问题是:
- 请情标注较多时不可避免的出现卡顿,所以请求时只请求当前面的标注。
- 点击详情标注时将标注移动到地图中央,同时请求当前页标注,
请求回来后要再次判断当前页面放大级别。另外为了有点击回馈,
实现了点击和取消点的方法。 - 整个项目的这种做法,虽然实现了所有功能,但仍有卡顿感。
应该还有更好的实现方法或优化空间。