点标记
点标记,即Annotation,用于在地图中标记位置,如POI位置、车辆位置等带有位置属性的事物。
腾讯地图SDK点标记功能分为两个部分,点标记数据对象(Annotation)和点标记的信息窗(CalloutView)。
Annotation和CalloutView提供了默认样式,同时也可以自定义样式。
添加默认样式点标记
SDK提供了默认的点标记数据对象(QPointAnnotation)和默认的大头针样式点标注View(QPinAnnotationView),基本使用步骤如下:
-
创建点标记数据对象,QPointAnnotation提供了点标记的位置、标题等信息:
QPointAnnotation *pointAnnotation = [[QPointAnnotation alloc] init]; pointAnnotation.coordinate = CLLocationCoordinate2DMake(40.040219, 116.273348); // 点标注的标题 pointAnnotation.title = @"腾讯"; // 副标题 pointAnnotation.subtitle = @"腾讯北京总部"; // 将点标记添加到地图中 [self.mapView addAnnotation:pointAnnotation];
-
实现<QMapViewDelegate>协议的
mapView:viewForAnnotation:
方法,创建点标注:- (QAnnotationView *)mapView:(QMapView *)mapView viewForAnnotation:(id<QAnnotation>)annotation { if ([annotation isKindOfClass:[QPointAnnotation class]]) { static NSString *annotationIdentifier = @"pointAnnotation"; QPinAnnotationView *pinView = (QPinAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:annotationIdentifier]; if (pinView == nil) { pinView = [[QPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:annotationIdentifier]; pinView.canShowCallout = YES; } return pinView; } return nil; }
-
效果如下图所示:
自定义样式点标记
腾讯地图SDK可以自定义点标记样式,包括自定义点标记和自定义点标记信息窗口:
1. 自定义点标记图标
如果默认的点标记样式无法满足需求,可以在创建QPinAnnotationView时自定义点标记图标:
// 修改点标记图标
pinView.image = [UIImage imageNamed:@"greenPin"];
效果如图所示:
2. 自定义信息窗口
通过自定义信息窗口,可以展示更多标记点的信息,步骤如下:
自定义信息窗口类,示例代码如下:
#import <UIKit/UIKit.h>
@interface CustomCalloutView : UIView
// 图标
@property (nonatomic, strong) UIImage *image;
// 标题
@property (nonatomic, strong) NSString *title;
// 地址
@property (nonatomic, strong) NSString *address;
@end
#import "CustomCalloutView.h"
@interface CustomCalloutView ()
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UILabel *addressLabel;
@property (nonatomic, strong) UIImageView *coverImageView;
@end
@implementation CustomCalloutView
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.backgroundColor = [UIColor colorWithRed:124/255.0 green:238/255.0 blue:240/255.0 alpha:1];
[self initSubviews];
}
return self;
}
- (void)initSubviews {
CGFloat margin = 5;
// 图标控件
self.coverImageView = [[UIImageView alloc] initWithFrame:CGRectMake(margin, margin, 50, 50)];
[self addSubview:self.coverImageView];
// 标题控件
self.titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(margin * 2 + 50, margin, 50, 20)];
self.titleLabel.font = [UIFont systemFontOfSize:15];
self.titleLabel.textColor = [UIColor blackColor];
[self addSubview:self.titleLabel];
// 地址控件
self.addressLabel = [[UILabel alloc] initWithFrame:CGRectMake(margin * 2 + 50, 35, 50, 20)];
self.addressLabel.font = [UIFont systemFontOfSize:12];
self.addressLabel.textColor = [UIColor blackColor];
[self addSubview:self.addressLabel];
}
- (void)setTitle:(NSString *)title {
_title = title;
self.titleLabel.text = title;
}
- (void)setAddress:(NSString *)address {
_address = address;
self.addressLabel.text = address;
}
- (void)setImage:(UIImage *)image {
_image = image;
self.coverImageView.image = image;
}
@end
在创建Annotation时,指定customCalloutView属性,示例代码如下:
- (QAnnotationView *)mapView:(QMapView *)mapView viewForAnnotation:(id<QAnnotation>)annotation
{
if ([annotation isKindOfClass:[QPointAnnotation class]])
{
static NSString *pointReuseIndetifier = @"pointReuseIndetifier";
QPinAnnotationView *annotationView = (QPinAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:pointReuseIndetifier];
// 取出自定义信息窗口控件
CustomCalloutView *customCalloutView = (CustomCalloutView *)annotationView.customCalloutView;
if (annotationView == nil)
{
annotationView = [[QPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:pointReuseIndetifier];
annotationView.canShowCallout = YES;
// 如果annotationView为新创建,同时创建customCalloutView并赋值
customCalloutView = [[CustomCalloutView alloc] initWithFrame:CGRectMake(0, 0, 15 + 100, 10 + 50)];
annotationView.customCalloutView = customCalloutView;
}
customCalloutView.image = [UIImage imageNamed:@"good"];
customCalloutView.title = annotation.title;
customCalloutView.address = annotation.subtitle;
return annotationView;
}
return nil;
}
3. 效果如图所示:
点标记的删除和批量操作
单独添加一个点标记,已经在添加默认样式点标记中介绍了,本小结将介绍如何删除单个点标记、批量添加点标记和批量删除点标记。
-
删除单个点标记:
[self.mapView removeAnnotation:annotation];
-
批量添加点标记:
[self.mapView addAnnotations:annotationArray];
-
批量删除点标记
[self.mapView removeAnnotations:annotationArray];
点标记的动画效果和拖拽效果
点标记在添加到地图中时,可以添加动画效果,点标记会添加掉落动画:
annotationView.animatesDrop = YES;
通过对点标记进行长按手势,可以将点标记拖动到其他的位置:
annotationView.draggable = YES;
点标记的事件监听
点标记默认可以响应点击事件并切换到选中状态,事件响应可以控制开启、关闭。实现<QMapViewDelegate>中的代理方法,可以监听点标记的事件。
-
点标记的事件响应开关:
// 默认为YES, 当为NO时view忽略触摸事件 annotationView.enable = NO; // 获取当前点标记是否处于选中状态 if (annotationView.selected) { ... }
-
点标注的监听方法
// 当mapView新添加annotation views时,调用此接口 - (void)mapView:(QMapView *)mapView didAddAnnotationViews:(NSArray<QAnnotationView *> *)views; // 当选中一个annotation view时,调用此接口 - (void)mapView:(QMapView *)mapView didSelectAnnotationView:(QAnnotationView *)view; // 当取消选中一个annotation view时,调用此接口 - (void)mapView:(QMapView *)mapView didDeselectAnnotationView:(QAnnotationView *)view; // 拖动annotationView时view的状态变化 - (void)mapView:(QMapView *)mapView annotationView:(QAnnotationView *)view didChangeDragState:(QAnnotationViewDragState)newState fromOldState:(QAnnotationViewDragState)oldState;
-
点标注的拖动状态:QAnnotationViewDragState
状态 说明 QAnnotationViewDragStateNone 静止状态 QAnnotationViewDragStateStarting 开始拖动 QAnnotationViewDragStateDragging 拖动中 QAnnotationViewDragStateCanceling 取消拖动 QAnnotationViewDragStateEnding 拖动结束
点标记与地图POI元素的碰撞
腾讯地图SDK自4.4.1版本起,支持点标记与地图POI元素的碰撞功能,当开启碰撞功能时,与点标记重合的POI元素将会被隐藏,示例代码如下:
/**
* @enum QAnnotationViewCollisionType
* QAnnotationView的碰撞类型
*/
/*
typedef enum {
QAnnotationViewCollisionTypeNone,
QAnnotationViewCollisionWithLabel = 1, /// 可以与地图POI元素碰撞
} QAnnotationViewCollisionType;
*/
- (QAnnotationView *)mapView:(QMapView *)mapView viewForAnnotation:(id<QAnnotation>)annotation {
static NSString *annotationId = @"id";
QPinAnnotationView *pinView = [mapView dequeueReusableAnnotationViewWithIdentifier:annotationId];
if (pinView == nil) {
pinView = [[QPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:annotationId];
pinView.collisionType = QAnnotationViewCollisionWithLabel;
}
return pinView;
}
示例图如下(左侧为开启碰撞,右侧为关闭碰撞):
常用方法
- 调增地图显示范围,使其显示范围内的所有点标记:
-
获取构成Annotation、Polyline和多边形的的坐标
-
计算这些坐标构成的最小外接region
-
更新地图显示region
// 点标注坐标 CLLocationCoordinate2D coordinates[4]; coordinates[0] = CLLocationCoordinate2DMake(40.041554,116.271508); coordinates[1] = CLLocationCoordinate2DMake(40.041652,116.274619); coordinates[2] = CLLocationCoordinate2DMake(40.03863,116.271787); coordinates[3] = CLLocationCoordinate2DMake(40.038745,116.275134); // 计算最小外接区域 QCoordinateRegion region = QBoundingCoordinateRegionWithCoordinates(coordinates, 4); // 更新可见region [self.mapView setRegion:region edgePadding:UIEdgeInsetsZero animated:YES];
-
效果如图所示:
-
常见问题
-
多个点标记距离较近,出现相互覆盖的情况
AnnotationView提供了zIndex属性,该值默认为0,值大的会覆盖在值小的上面。
-
如何添加海量点标记
Marker是绘制在地图之上的图片资源,当使用海量的Marker数据时,为了性能体验,建议使用点聚合来辅助显示