点标记用来在地图上标记任何位置,例如用户位置、车辆位置、店铺位置等一切带有位置属性的事物。
百度地图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)
实现 <BMKMapViewDelegate> 协议中的 mapView:viewForAnnotation:回调函数,设置标注样式。代码如下所示:
#pragma mark - BMKMapViewDelegate - (BMKAnnotationView *)mapView:(BMKMapView *)mapView viewForAnnotation:(id <BMKAnnotation>)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 <BMKAnnotation>)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 <UIKit/UIKit.h> @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 <BMKAnnotation>)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)
简介
Since 6.5.0 iOS地图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])
实现 <BMKMapViewDelegate> 协议中的 mapView:viewForAnnotation:回调函数,设置标注样式。代码如下所示:
#pragma mark - BMKMapViewDelegate - (BMKAnnotationView *)mapView:(BMKMapView *)mapView viewForAnnotation:(id<BMKAnnotation>)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 }
效果如下