点标记用来在地图上标记任何位置,例如用户位置、车辆位置、店铺位置等一切带有位置属性的事物。
百度地图ios sdk 提供的点标记功能包含两大部分,一部分是点(俗称annotation)、另一部分是浮于点上方的信息窗体(俗称 paopaoview)。同时,sdk对annotation和paopaoview封装了大量的触发事件,例如点击事件、长按事件、拖拽事件。
annotation和 paopaoview 有默认风格,同时也支持自定义。
ios地图sdk预置了基本的标注点(bmkpointannotation)和一个大头针标注view(bmkpinannotationview),您可以直接使用来显示标注。
ios地图sdk提供的大头针标注bmkpinannotationview,通过它可以设置大头针颜色、是否显示动画等。
bmkpointannotation* annotation = [[bmkpointannotation alloc]init]; annotation.coordinate = cllocationcoordinate2dmake(39.915, 116.404); //设置标注的标题 annotation.title = @"北京"; //副标题 annotation.subtitle = @"天安门"; [_mapview addannotation:annotation];
//初始化标注类bmkpointannotation的实例 annotation = bmkpointannotation.init() //设置标注的经纬度坐标 annotation?.coordinate = cllocationcoordinate2d(latitude: 39.915, longitude: 116.404) //设置标注的标题 annotation?.title = "北京" //副标题 annotation?.subtitle = "天安门" /** 当前地图添加标注,需要实现bmkmapviewdelegate的-mapview:viewforannotation:方法 来生成标注对应的view @param annotation 要添加的标注 */ mapview.addannotation(annotation)
实现
#pragma mark - bmkmapviewdelegate - (bmkannotationview *)mapview:(bmkmapview *)mapview viewforannotation:(id)annotation { if ([annotation iskindofclass:[bmkpointannotation class]]) { static nsstring *reuseindetifier = @"annotationreuseindetifier"; bmkannotationview *annotationview = [mapview dequeuereusableannotationviewwithidentifier:reuseindetifier]; if (annotationview == nil) { annotationview = [[bmkannotationview alloc] initwithannotation:annotation reuseidentifier:reuseindetifier]; } return annotationview; } return nil; }
//mark:bmkmapviewdelegate /** 根据anntation生成对应的annotationview @param mapview 地图view @param annotation 指定的标注 @return 生成的标注view */ func mapview(_ mapview: bmkmapview!, viewfor annotation: bmkannotation!) -> bmkannotationview! { if annotation.iskind(of: bmkpointannotation.self) { /** 根据指定标识查找一个可被复用的标注,用此方法来代替新创建一个标注,返回可被复用的标注 */ var annotationview: bmkpinannotationview? = mapview.dequeuereusableannotationview(withidentifier: annotationviewidentifier) as? bmkpinannotationview if annotationview == nil { /** 初始化并返回一个annotationview @param annotation 关联的annotation对象 @param reuseidentifier 如果要重用view,传入一个字符串,否则设为nil,建议重用view @return 初始化成功则返回annotationview,否则返回nil */ annotationview = bmkpinannotationview.init(annotation: annotation, reuseidentifier: annotationviewidentifier) } return annotationview } return nil }
在地图显示对应的标注点,点击标注弹出气泡,效果如图:
ios 地图sdk可自定义标注(包括自定义标注图标和自定义气泡图标),均通过bmkannotationview来实现。
自定义标注图标
若大头针样式的标注不能满足您的需求,您可以自定义标注图标。代码如下:
#pragma mark - bmkmapviewdelegate - (bmkannotationview *)mapview:(bmkmapview *)mapview viewforannotation:(id)annotation { if ([annotation iskindofclass:[bmkpointannotation class]]) { static nsstring *reuseindetifier = @"annotationreuseindetifier"; bmkannotationview *annotationview = [mapview dequeuereusableannotationviewwithidentifier:reuseindetifier]; if (annotationview == nil) { annotationview = [[bmkannotationview alloc] initwithannotation:annotation reuseidentifier:reuseindetifier]; } annotationview.image = [uiimage imagenamed:@"poi.png"]; return annotationview; } return nil; }
//mark:bmkmapviewdelegate /** 根据anntation生成对应的annotationview @param mapview 地图view @param annotation 指定的标注 @return 生成的标注view */ func mapview(_ mapview: bmkmapview!, viewfor annotation: bmkannotation!) -> bmkannotationview! { if annotation.iskind(of: bmkpointannotation.self) { /** 根据指定标识查找一个可被复用的标注,用此方法来代替新创建一个标注,返回可被复用的标注 */ var annotationview: bmkpinannotationview? = mapview.dequeuereusableannotationview(withidentifier: annotationviewidentifier) as? bmkpinannotationview if annotationview == nil { /** 初始化并返回一个annotationview @param annotation 关联的annotation对象 @param reuseidentifier 如果要重用view,传入一个字符串,否则设为nil,建议重用view @return 初始化成功则返回annotationview,否则返回nil */ annotationview = bmkpinannotationview.init(annotation: annotation, reuseidentifier: annotationviewidentifier) //annotationview显示的图片,默认是大头针 annotationview?.image = uiimage.init(named: "poi.png") } return annotationview } return nil }
效果如图:
添加自定义气泡
气泡在ios中又称为paopaoview,它由背景和气泡内容构成。
自定义气泡类完整代码如下:
#import@interface custompaopaoview : uiview @property (nonatomic, strong) uiimage *image; //商户图 @property (nonatomic, copy) nsstring *title; //商户名 @property (nonatomic, copy) nsstring *subtitle; //地址 @end #import "custompaopaoview.h" #define kportraitmargin 5 #define kportraitwidth 50 #define kportraitheight 50 #define ktitlewidth 120 #define ktitleheight 20 #define karrorheight 0 @interface custompaopaoview () @property (nonatomic, strong) uiimageview *portraitview; @property (nonatomic, strong) uilabel *subtitlelabel; @property (nonatomic, strong) uilabel *titlelabel; @end @implementation custompaopaoview #pragma mark - draw rect - (void)drawrect:(cgrect)rect { [self drawincontext:uigraphicsgetcurrentcontext()]; self.layer.shadowcolor = [[uicolor blackcolor] cgcolor]; self.layer.shadowopacity = 1.0; self.layer.shadowoffset = cgsizemake(0.0f, 0.0f); } - (void)drawincontext:(cgcontextref)context { cgcontextsetlinewidth(context, 2.0); cgcontextsetfillcolorwithcolor(context, [uicolor colorwithred:0.3 green:0.3 blue:0.3 alpha:0.8].cgcolor); [self getdrawpath:context]; cgcontextfillpath(context); } - (void)getdrawpath:(cgcontextref)context { cgrect rrect = self.bounds; cgfloat radius = 6.0; cgfloat minx = cgrectgetminx(rrect), midx = cgrectgetmidx(rrect), maxx = cgrectgetmaxx(rrect); cgfloat miny = cgrectgetminy(rrect), maxy = cgrectgetmaxy(rrect)-karrorheight; cgcontextmovetopoint(context, midx karrorheight, maxy); cgcontextaddlinetopoint(context,midx, maxy karrorheight); cgcontextaddlinetopoint(context,midx-karrorheight, maxy); cgcontextaddarctopoint(context, minx, maxy, minx, miny, radius); cgcontextaddarctopoint(context, minx, minx, maxx, miny, radius); cgcontextaddarctopoint(context, maxx, miny, maxx, maxx, radius); cgcontextaddarctopoint(context, maxx, maxy, midx, maxy, radius); cgcontextclosepath(context); } - (id)initwithframe:(cgrect)frame { self = [super initwithframe:frame]; if (self) { self.backgroundcolor = [uicolor clearcolor]; [self initsubviews]; } return self; } - (void)initsubviews { // 添加图片,即商户图 self.portraitview = [[uiimageview alloc] initwithframe:cgrectmake(kportraitmargin, kportraitmargin, kportraitwidth, kportraitheight)]; self.portraitview.backgroundcolor = [uicolor blackcolor]; [self addsubview:self.portraitview]; // 添加标题,即商户名 self.titlelabel = [[uilabel alloc] initwithframe:cgrectmake(kportraitmargin * 2 kportraitwidth, kportraitmargin, ktitlewidth, ktitleheight)]; self.titlelabel.font = [uifont boldsystemfontofsize:14]; self.titlelabel.textcolor = [uicolor whitecolor]; self.titlelabel.text = self.title; [self addsubview:self.titlelabel]; // 添加副标题,即商户地址 self.subtitlelabel = [[uilabel alloc] initwithframe:cgrectmake(kportraitmargin * 2 kportraitwidth, kportraitmargin * 2 ktitleheight, ktitlewidth, ktitleheight)]; self.subtitlelabel.font = [uifont systemfontofsize:12]; self.subtitlelabel.textcolor = [uicolor lightgraycolor]; self.subtitlelabel.text = self.subtitle; [self addsubview:self.subtitlelabel]; } - (void)settitle:(nsstring *)title { self.titlelabel.text = title; } - (void)setsubtitle:(nsstring *)subtitle { self.subtitlelabel.text = subtitle; } - (void)setimage:(uiimage *)image { self.portraitview.image = image; } @end
以上就是自定义气泡类的全部示例代码,在点击标注时实现弹出自定义的气泡的效果,还需要在bmkmapview的代理方法mapview: viewforannotation:设置自定义的paopaoview,完整代码如下:
#pragma mark - bmkmapviewdelegate - (bmkannotationview *)mapview:(bmkmapview *)mapview viewforannotation:(id)annotation { if ([annotation iskindofclass:[bmkpointannotation class]]) { static nsstring *reuseindetifier = @"annotationreuseindetifier"; bmkannotationview *annotationview = [mapview dequeuereusableannotationviewwithidentifier:reuseindetifier]; if (annotationview == nil) { annotationview = [[bmkannotationview alloc] initwithannotation:annotation reuseidentifier:reuseindetifier]; } annotationview.image = [uiimage imagenamed:@"poi.png"]; annotationview.canshowcallout = yes; custompaopaoview *custompopview = [[custompaopaoview alloc] init]; custompopview.frame = cgrectmake(0, 0, 120.0f, 70.0f); custompopview.image = [uiimage imagenamed:@"poi.png"]; custompopview.title = @"北京"; custompopview.subtitle = @"天安门"; bmkactionpaopaoview *pview = [[bmkactionpaopaoview alloc] initwithcustomview:custompopview]; pview.backgroundcolor = [uicolor lightgraycolor]; pview.frame = custompopview.frame; annotationview.paopaoview = pview; return annotationview; } return nil; }
效果如图:
删除单个点标记
//删除指定的单个点标记 [_mapview removeannotation:annotation];
//删除指定的单个点标记 mapview?.removeannotation(annotation)
批量添加annotation
/** *向地图窗口添加一组标注,需要实现bmkmapviewdelegate的-mapview:viewforannotation:函数来生成标注对应的view *@param annotations 要添加的标注数组 */ [_mapview addannotations:annotations];
/** *向地图窗口添加一组标注,需要实现bmkmapviewdelegate的-mapview:viewforannotation:函数来生成标注对应的view *@param annotations 要添加的标注数组 */ mapview?.addannotations(annotations)
批量删除annotation
/** *移除一组标注 *@param annotation 要移除的标注数组 */ [_mapview removeannotations:annotations];
/** *移除一组标注 *@param annotation 要移除的标注数组 */ mapview?.removeannotations(annotations)
简介
ios7.5.0 起地图sdk支持点标记碰撞策略功能
碰撞策略相关属性
bmkannotationview新增以下属性,整体碰撞策略优先级:层级限制>强制展示>碰撞优先级>展示优先级>添加顺序
属性 | 类型 | 说明 |
---|---|---|
displaymaxlevel | float | 需要展示的最大级别,大于此级别则不展示,默认22。v6.5.0以后支持 |
displayminlevel | float | 需要展示的最小级别,小于此级别则不展示,默认4。v6.5.0以后支持 |
isopencollisiondetection | bool | 开启碰撞检测,默认no,关闭。v6.5.0以后支持 |
collisiondetectionpriority | nsinteger | 碰撞检测优先级,同一优先级后添加的优先展示。v6.5.0以后支持,默认为0 |
isforcedisplay | bool | 开启碰撞检测时,是否强制展示,默认no。v6.5.0以后支持 |
实现
nsmutablearray *annotations = [nsmutablearray array]; for (nsinteger i = 0; i < 20; i ) { double lat = (arc4random() % 100) * 0.001; double lon = (arc4random() % 100) * 0.001; bmkpointannotation *annotation = [[bmkpointannotation alloc] init]; annotation.coordinate = cllocationcoordinate2dmake(_basicannotationcoordinate.latitude lat, _basicannotationcoordinate.longitude lon); annotation.title = @"绿"; [annotations addobject:annotation]; } [self.mapview addannotations:annotations];
let annotations = nsmutablearray(); for _ in 0..<20 { let lat = double((arc4random() % 100)) * 0.001 let lon = double((arc4random() % 100)) * 0.001 let annotation = bmkpointannotation() annotation.coordinate = cllocationcoordinate2d(latitude: basicannotationcoordinate!.latitude lat, longitude: basicannotationcoordinate!.longitude lon) annotation.title = "绿" annotations.add(annotation); } mapview.addannotations(annotations as! [bmkannotation])
实现
#pragma mark - bmkmapviewdelegate - (bmkannotationview *)mapview:(bmkmapview *)mapview viewforannotation:(id)annotation { bmkpinannotationview *pinannotationview = (bmkpinannotationview *)[mapview dequeuereusableannotationviewwithidentifier:annotationviewidentifier]; if (!pinannotationview) { pinannotationview = [[bmkpinannotationview alloc] initwithannotation:annotation reuseidentifier:annotationviewidentifier]; } if ([annotation.title isequaltostring:@"红"]) { pinannotationview.pincolor = bmkpinannotationcolorred; // 强制展示 pinannotationview.isforcedisplay = yes; } else if ([annotation.title isequaltostring:@"紫"]) { pinannotationview.pincolor = bmkpinannotationcolorpurple; // 最大展示级别 pinannotationview.displaymaxlevel = 19; // 最小展示级别 pinannotationview.displayminlevel = 10; } else { pinannotationview.pincolor = bmkpinannotationcolorgreen; } // 开启碰撞检测 pinannotationview.isopencollisiondetection = yes; return pinannotationview; }
//mark:bmkmapviewdelegate /** 根据anntation生成对应的annotationview @param mapview 地图view @param annotation 指定的标注 @return 生成的标注view */ func mapview(_ mapview: bmkmapview, viewfor annotation: bmkannotation) -> bmkannotationview? { var annotationview: bmkpinannotationview? = mapview.dequeuereusableannotationview(withidentifier: annotationviewidentifier) as? bmkpinannotationview if annotationview == nil { annotationview = bmkpinannotationview.init(annotation: annotation, reuseidentifier: annotationviewidentifier) } if annotation.title?() == "红" { annotationview!.pincolor = uint(bmkpinannotationcolorred); // 强制展示 annotationview!.isforcedisplay = true; } else if annotation.title?() == "紫" { annotationview!.pincolor = uint(bmkpinannotationcolorpurple); // 最大展示级别 annotationview!.displaymaxlevel = 19 // 最小展示级别 annotationview!.displayminlevel = 10 } else { annotationview!.pincolor = uint(bmkpinannotationcolorgreen) } // 开启碰撞检测 annotationview!.isopencollisiondetection = true return annotationview }
效果如下