做開發(fā)有一段時(shí)間了,第一次寫文章,主要記錄下使用百度地圖中遇到的比較棘手的問題以及解決辦法,直接進(jìn)入主題吧,最近項(xiàng)目中遇到一個(gè)需求,在地圖zoomlevel較小的時(shí)候地圖標(biāo)注只顯示一個(gè)圖片,此時(shí)圖片可以點(diǎn)擊,然后顯示詳情view(數(shù)據(jù)較復(fù)雜),詳情view也有點(diǎn)擊事件,也可以點(diǎn)擊,然后彈出另一個(gè)controller,效果大致如下:
在地圖zoomlevel被放大到一定程度后,不需要點(diǎn)擊,自動(dòng)顯示所有的自定義view,效果如圖:
筆者主要記錄如何解決這個(gè)需求,如何配置地圖以及定位等基礎(chǔ)功能詳情請(qǐng)參考官方文檔或者我給出的Demo都有詳細(xì)的注釋,先說下我的解決思路吧,首先拿到數(shù)據(jù)后,在地圖上將點(diǎn)都描出來(lái)(自定義view的數(shù)據(jù)信息是小圖標(biāo)的詳情,所以經(jīng)緯度是一樣的),注意是把小圖標(biāo)和自定義view都作為標(biāo)注點(diǎn)描出來(lái),通過調(diào)節(jié)centeroffset,frame等屬性使得兩個(gè)標(biāo)注的位置如上需求圖所示,
/**
隨機(jī)模擬數(shù)據(jù)
*/
- (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;
//為了保證數(shù)據(jù)一樣,所以用數(shù)組將隨機(jī)產(chǎn)生的將緯度存起來(lái)
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;
}
//用兩個(gè)for循環(huán)是為了保證自定義的annotionview點(diǎn)在最下面,(先添加的點(diǎn)在地圖最下方,安卓有一個(gè)屬性可以設(shè)置覆蓋物層級(jí)關(guān)系,但是ios目前還沒有這個(gè)屬性)
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方法里面來(lái)更改圖片需要顯示的圖片樣式,這里比較簡(jiǎn)單,只需要顯示一張圖片,所以就系統(tǒng)的BMKAnnotationView就可以了,然后設(shè)置圖片,annotationView.image= [UIImageimageNamed:@"你需要顯示的圖片名字"]即可;,這里會(huì)有一個(gè)問題,如果圖片比較小,你在點(diǎn)擊的時(shí)候有可能要點(diǎn)很多次才能準(zhǔn)確點(diǎn)擊到你想要點(diǎn)擊的點(diǎn),這里解決辦法是重寫B(tài)MKAnnotationView的初始化方法,在里面設(shè)置其frame,自定義一個(gè)BMKAnnotationView,然后在.h中添加一個(gè)image,imageview屬性用于顯示你需要的圖片

然后在.m中實(shí)現(xiàn)如下方法,也就是給self添加image。此時(shí)在viewForAnnotation設(shè)置圖片的時(shí)候就需要使用你自定義的屬性annimage來(lái)設(shè)置圖片了annotationView.annimage= [UIImage imageNamed:@"地災(zāi)點(diǎn).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];
}
如何將那個(gè)自定義view也作為標(biāo)注點(diǎn)顯示呢,官方api都只是給出了一個(gè)image屬性供我們?cè)O(shè)置,這里也只能自定義來(lái)處理了,依然是重寫B(tài)MKAnnotationView的初始化方法,在初始化方法中在添加一個(gè)uiview參數(shù),在初始化的時(shí)候?qū)⒛阈枰@示的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);//設(shè)置中心點(diǎn)偏移
[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];
//設(shè)置顏色
//annotationView.pinColor = BMKPinAnnotationColorPurple;
//從天上掉下效果
annotationView.annimage= [UIImageimageNamed:@"地災(zāi)點(diǎn).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;//設(shè)置一個(gè)tag值方便后面顯示隱藏調(diào)用
CustomAnnotationView*customAnnotationView = [[CustomAnnotationViewalloc]initWithAnnotation:annotationreuseIdentifier:@"CustomID"customView:self.customView];//將你需要自定義的view傳給他自己的初始化方法
returncustomAnnotationView;
}
returnnil;
}
此時(shí)點(diǎn)已經(jīng)在地圖上描出來(lái)了,然后就是點(diǎn)擊這個(gè)標(biāo)注的響應(yīng)事件,百度地圖中有一個(gè)代理類似于tableview的選中某行方法,-(void)mapView:(BMKMapView*)mapView didSelectAnnotationView:(BMKAnnotationView*)view
在這個(gè)方法里將你需要顯示的詳情view加載出來(lái),然后在地圖zoomlevel較小的時(shí)候?qū)⑵湓O(shè)置成當(dāng)前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的另一個(gè)代理方法中判斷zoomlevel,來(lái)決定是否要顯示自定義view那個(gè)標(biāo)注了
*地圖渲染每一幀畫面過程中,以及每次需要重繪地圖時(shí)(例如添加覆蓋物)都會(huì)調(diào)用此接口
*@param mapView地圖View
*@param status此時(shí)地圖的狀態(tài)
*/
- (void)mapView:(BMKMapView*)mapView onDrawMapFrame:(BMKMapStatus*)status {
NSLog(@"%f",mapView.zoomLevel);
if(mapView.zoomLevel>ZOOMLEVEL) {
if(!isSuccessLocation) {//地圖在定位過程中zoomlevel波動(dòng)較大,所以在定位成功后用isSuccessLocation來(lái)標(biāo)記
for(BMKPointAnnotation*annincustomPointArr) {
BMKAnnotationView* annView = [_mapViewviewForAnnotation:ann];
UIView*view = [annViewviewWithTag:111222333];
[viewsetHidden:NO];
}
//防止在地圖放大之前用戶已經(jīng)選中某個(gè)點(diǎn)了
[mapViewdeselectAnnotation:seleView.annotationanimated:YES];
isSuccessLocation=YES;//避免地圖放大過程中頻繁調(diào)用此方法,所以在zoomlevel大于ZOOMLEVEL后就一直顯示自定義view
}
}else{
if(isSuccessLocation) {
for(BMKPointAnnotation*annincustomPointArr) {
BMKAnnotationView* annView = [_mapView viewForAnnotation:ann];
UIView*view = [annView viewWithTag:111222333];
[viewsetHidden:YES];
}
isSuccessLocation=NO;
}
}
}
到這里重點(diǎn)部分已經(jīng)講的差不多了,第一次寫文章,可能在邏輯上表達(dá)不是很清楚,有不清楚的地方看demo相信能解決你類似的需求的,附上github鏈接 demo下載地址,有什么不足或有什么其他實(shí)現(xiàn)思路的的可以一起交流討論。