做开发有一段时间了,第一次写文章,主要记录下使用百度地图中遇到的比较棘手的问题以及解决办法,直接进入主题吧,最近项目中遇到一个需求,在地图zoomlevel较小的时候地图标注只显示一个图片,此时图片可以点击,然后显示详情view(数据较复杂),详情view也有点击事件,也可以点击,然后弹出另一个controller,效果大致如下:
在地图zoomlevel被放大到一定程度后,不需要点击,自动显示所有的自定义view,效果如图:
笔者主要记录如何解决这个需求,如何配置地图以及定位等基础功能详情请参考官方文档或者我给出的Demo都有详细的注释,先说下我的解决思路吧,首先拿到数据后,在地图上将点都描出来(自定义view的数据信息是小图标的详情,所以经纬度是一样的),注意是把小图标和自定义view都作为标注点描出来,通过调节centeroffset,frame等属性使得两个标注的位置如上需求图所示,
/**
随机模拟数据
*/
- (void)getShowData:(CLLocationCoordinate2D)coor {
imagePointArr= [NSMutableArray array];
customPointArr= [NSMutableArray array];
NSMutableArray*dataArr = [NSMutableArray array];
for(inti =0; i <20; i++) {
doublelat =(arc4random() %100) *0.001f;
doublelon =(arc4random() %100) *0.001f;
//为了保证数据一样,所以用数组将随机产生的将纬度存起来
CLLocationCoordinate2D coorrr =CLLocationCoordinate2DMake(coor.latitude+ lat, coor.longitude+ lon);
NSDictionary *latLonDic =@{@"lat":[NSStringstringWithFormat:@"%f",coorrr.latitude],@"lon":[NSString stringWithFormat:@"%f",coorrr.longitude]};
[dataArr addObject:latLonDic];
customPointAnnotation= [[BMKPointAnnotation alloc]init];
customPointAnnotation.coordinate= coorrr;
customPointAnnotation.title= [NSString stringWithFormat:@"%d",i];
[customPointArr addObject:customPointAnnotation];
[_mapView addAnnotation:customPointAnnotation];
BMKAnnotationView *detailView = [_mapView viewForAnnotation:customPointAnnotation];
detailView.tag=20000+ i;
}
//用两个for循环是为了保证自定义的annotionview点在最下面,(先添加的点在地图最下方,安卓有一个属性可以设置覆盖物层级关系,但是ios目前还没有这个属性)
for(inti =0; i <20; i++) {
CLLocationCoordinate2D coorrr =CLLocationCoordinate2DMake([dataArr[i][@"lat"]doubleValue], [dataArr[i][@"lon"]doubleValue]);
imagePointAnnotation= [[BMKPointAnnotation alloc]init];
imagePointAnnotation.coordinate= coorrr;
imagePointAnnotation.title= [NSStringstringWithFormat:@"%d",i];
[imagePointArr addObject:imagePointAnnotation];
[_mapView addAnnotation:imagePointAnnotation];
BMKAnnotationView* aview = [_mapView viewForAnnotation:imagePointAnnotation];
aview.tag=10000+i;
}
}
然后在- (BMKAnnotationView*)mapView:(BMKMapView*)mapView viewForAnnotation:(id)annotation方法里面来更改图片需要显示的图片样式,这里比较简单,只需要显示一张图片,所以就系统的BMKAnnotationView就可以了,然后设置图片,annotationView.image= [UIImageimageNamed:@"你需要显示的图片名字"]即可;,这里会有一个问题,如果图片比较小,你在点击的时候有可能要点很多次才能准确点击到你想要点击的点,这里解决办法是重写BMKAnnotationView的初始化方法,在里面设置其frame,自定义一个BMKAnnotationView,然后在.h中添加一个image,imageview属性用于显示你需要的图片
然后在.m中实现如下方法,也就是给self添加image。此时在viewForAnnotation设置图片的时候就需要使用你自定义的属性annimage来设置图片了annotationView.annimage= [UIImage imageNamed:@"地灾点.png"];
- (id)initWithAnnotation:(id)annotation reuseIdentifier:(NSString*)reuseIdentifier {
if(self= [super initWithAnnotation:annotationreuseIdentifier:reuseIdentifier]) {
[self setBounds:CGRectMake(0.f,0.f,50.f,50.f)];
[self setBackgroundColor:[UIColorclearColor]];
_annotationImageView= [[UIImageViewalloc]initWithFrame:self.bounds];
_annotationImageView.contentMode=UIViewContentModeCenter;
[selfaddSubview:_annotationImageView];
}
returnself;
}
- (void)setAnnimage:(UIImage*)annimage {
_annimage= annimage;
[self updateImageView];
}
- (void)updateImageView {
if([_annotationImageView isAnimating]) {
[_annotationImageView stopAnimating];
}
_annotationImageView.image=_annimage;
_annotationImageView.animationDuration=0.5;
_annotationImageView.animationRepeatCount=0;
[_annotationImageView startAnimating];
}
如何将那个自定义view也作为标注点显示呢,官方api都只是给出了一个image属性供我们设置,这里也只能自定义来处理了,依然是重写BMKAnnotationView的初始化方法,在初始化方法中在添加一个uiview参数,在初始化的时候将你需要显示的view传过去,代码如下:
- (id)initWithAnnotation:(id)annotation reuseIdentifier:(NSString*)reuseIdentifier customView:(UIView*)detailView {
if(self= [super initWithAnnotation:annotationreuseIdentifier:reuseIdentifier]) {
[self setBounds:CGRectMake(0.f,0.f,142.f,120.f)];
self.backgroundColor= [UIColor clearColor];
self.canShowCallout=NO;
self.centerOffset=CGPointMake(40, -80);//设置中心点偏移
[self addSubview:detailView];
}
returnself;
}
viewForAnnotation代理方法中代码如下:
- (BMKAnnotationView*)mapView:(BMKMapView*)mapView viewForAnnotation:(id)annotation {
if(annotation ==imagePointAnnotation) {
NSString*AnnotationViewID =@"imageMark";
ImageAnnoTationView*annotationView = [[ImageAnnoTationView alloc]initWithAnnotation:annotationreuseIdentifier:AnnotationViewID];
//设置颜色
//annotationView.pinColor = BMKPinAnnotationColorPurple;
//从天上掉下效果
annotationView.annimage= [UIImageimageNamed:@"地灾点.png"];
//annotationView.animatesDrop = YES;
returnannotationView;
}elseif(annotation ==customPointAnnotation) {
[[NSBundlemainBundle]loadNibNamed:@"PredictView"owner:selfoptions:nil];
self.customView.frame=CGRectMake(0,0,142,120);
self.customView.tag=111222333;//设置一个tag值方便后面显示隐藏调用
CustomAnnotationView*customAnnotationView = [[CustomAnnotationViewalloc]initWithAnnotation:annotationreuseIdentifier:@"CustomID"customView:self.customView];//将你需要自定义的view传给他自己的初始化方法
returncustomAnnotationView;
}
returnnil;
}
此时点已经在地图上描出来了,然后就是点击这个标注的响应事件,百度地图中有一个代理类似于tableview的选中某行方法,-(void)mapView:(BMKMapView*)mapView didSelectAnnotationView:(BMKAnnotationView*)view
在这个方法里将你需要显示的详情view加载出来,然后在地图zoomlevel较小的时候将其设置成当前BMKAnnotationView的paopaoview
-(void)mapView:(BMKMapView*)mapView didSelectAnnotationView:(BMKAnnotationView*)view {
if(view.tag>=10000&& view.tag<20000) {
seleView= view;
[[NSBundlemainBundle]loadNibNamed:@"PredictView"owner:selfoptions:nil];
UIView*areaPaoView=[[UIView alloc]initWithFrame:CGRectMake(0,0,242,125)];
self.customView.frame=CGRectMake(90,0,142,120);
[areaPaoView addSubview:self.customView];
BMKActionPaopaoView*paopao=[[BMKActionPaopaoView alloc]initWithCustomView:areaPaoView];
view.paopaoView.hidden=YES;
if(mapView.zoomLevel>ZOOMLEVEL) {
return;
}else{
view.paopaoView= paopao;
}
}elseif(view.tag>=20000&& view.tag<30000) {
if(mapView.zoomLevel
return;
}
[selfpopVC];
}
}
最后就是在mapview的另一个代理方法中判断zoomlevel,来决定是否要显示自定义view那个标注了
*地图渲染每一帧画面过程中,以及每次需要重绘地图时(例如添加覆盖物)都会调用此接口
*@param mapView地图View
*@param status此时地图的状态
*/
- (void)mapView:(BMKMapView*)mapView onDrawMapFrame:(BMKMapStatus*)status {
NSLog(@"%f",mapView.zoomLevel);
if(mapView.zoomLevel>ZOOMLEVEL) {
if(!isSuccessLocation) {//地图在定位过程中zoomlevel波动较大,所以在定位成功后用isSuccessLocation来标记
for(BMKPointAnnotation*annincustomPointArr) {
BMKAnnotationView* annView = [_mapViewviewForAnnotation:ann];
UIView*view = [annViewviewWithTag:111222333];
[viewsetHidden:NO];
}
//防止在地图放大之前用户已经选中某个点了
[mapViewdeselectAnnotation:seleView.annotationanimated:YES];
isSuccessLocation=YES;//避免地图放大过程中频繁调用此方法,所以在zoomlevel大于ZOOMLEVEL后就一直显示自定义view
}
}else{
if(isSuccessLocation) {
for(BMKPointAnnotation*annincustomPointArr) {
BMKAnnotationView* annView = [_mapView viewForAnnotation:ann];
UIView*view = [annView viewWithTag:111222333];
[viewsetHidden:YES];
}
isSuccessLocation=NO;
}
}
}
到这里重点部分已经讲的差不多了,第一次写文章,可能在逻辑上表达不是很清楚,有不清楚的地方看demo相信能解决你类似的需求的,附上github链接 demo下载地址,有什么不足或有什么其他实现思路的的可以一起交流讨论。