点聚合


当地图上需要展示的marker过多,可能会导致界面上marker出现压盖,展示不全,并导致整体性能变差,用户使用卡顿的显现。针对此类问题,推出点聚合能力,将大量Maker通过聚合的方式进行展示。


点数据、聚合管理类介绍

QMUAnnotation点数据类

QMUAnnotation 类是可被聚合的原始点数据,用户获取数据后可创建对应的 QMUAnnotation。一般情况下以数组形式把大量的聚合点数据存储起来。

属性说明:

属性 说明
CLLocationCoordinate2D coordinate 地理坐标
NSString *title 标题
NSString *subtitle 副标题
QMUPoint point 代表其位置,被用于参与聚合运算。默认为墨卡托坐标

接口说明:

// 设置坐标
- (void)setCoordinate:(CLLocationCoordinate2D)newCoordinate

// 当子类有新添加字段时,子类有可能需要重载来帮助判断是不是同一个点
- (NSUInteger)hash; 

// 当子类有新添加字段时,子类有可能需要重载来帮助判断是不是同一个点
(BOOL)isEqual:(id)object; 

初始化示例:

QMUAnnotation *anno = [[QMUAnnotation alloc] init];
anno.title = @"clusterAnno";
anno.coordinate = CLLocationCoordinate2DMake(latitude, longitude);

QMUClusterManager构建点聚合管理类

当构建好所需的聚合点数据后,需要一个点聚合管理类 QMUClusterManager 将聚合点数据进行管理。

QMUClusterManager 为聚合点功能的入口,通过此类的实例来配置聚合功能,和管理数据。

属性说明:

属性 说明
CGFloat distance 聚合的范围,单位为屏幕坐标。
id delegate 代理类,实现其方法可用于自定义聚合的效果
QMapView *map map实例
int thresholdZoomlevel 当zoomLevel > thresholdZoomlevel时为只计算屏幕附近的聚合点;
当zoomLevel<=thresholdZoomlevel时计算所有的聚合点. 可根据数据分布设置为适合的值。
如果设置为>18或<4值时, 则只会采用一种策略。默认为7。

接口说明:

// 创建一个实例.
- (instancetype)initWithMap:(QMapView*)map;

// 添加原始被聚合点
- (void)addAnnotaion:(QMUAnnotation*)anno;

// 添加批量的原始被聚合点
- (void)addAnnotations:(NSArray*)annos;

// 移除原始被聚合点
- (void)removeAnnotaion:(QMUAnnotation*)anno;

// 移除批量的原始被聚合点
- (void)removeAnnotations:(NSArray*)annos;

// 移除所有的原始被聚合点
- (void)clearAnnotations;

/** @brief
 * 当你想强制重新聚合时调用。地图产生变化后需调用刷新聚合点状态
 * 如 mapView: regionDidChangeAnimated: gesture: 等地图区域状态回调接口
 * (当仅改配置如distance, threeholdZoomlevel时会需要)
 */
- (void)refreshCluster;

注意:如不在 mapView: regionDidChangeAnimated: gesture: 调用 refreshCluster, 当地图区域发生变化后,点聚合效果不会刷新,示例如下:

- (void)mapView:(QMapView *)mapView regionDidChangeAnimated:(BOOL)animated gesture:(BOOL)bGesture
{
    [self.manager refreshCluster];
}

初始化示例:

// 继承代理
@interface ClusterAnnoViewController () <QMUClusterProtocol>
@end  

// 聚合点数据数组
NSArray* datas = [self loadData];
// 基于当前的 mapView 进行初始化
self.manager = [[QMUClusterManager alloc] initWithMap:self.mapView];
// 设置代理
self.manager.delegate = self;

self.manager.distance = 56;
// 将聚合点数据传入
[self.manager addAnnotations:datas];

QMUClusterProtocol协议

QMUClusterProtocol 用于配置自定义的聚合效果,用户通过- (BOOL)clusterAnnotation: withAnnotation:接口配置自定义的聚合效果。

// 决定特定的2个点是否需要被聚合,只有当返回YES且符合距离时才会被聚合,如果不实现则任意两原始点都被聚合
- (BOOL)clusterAnnotation:(QMUAnnotation* )anno1 withAnnotation:(QMUAnnotation*)anno2
{
   // TypedClustableAnnotation 为 QMUAnnotation 的子类
   TypedClustableAnnotation *l = (TypedClustableAnnotation*)anno1;
   TypedClustableAnnotation* r = (TypedClustableAnnotation*)anno2;

    // type 的值为4时,该点不会被聚合
    if (l.type == 4 || r.type == 4) {
       return NO;
    }
}

示例如下:左上角的一个点( type 值为4)没有被聚合,其他的三个点被聚合在一起



构建点聚合View

通过 QMUClusterManager 将聚合点数据传入后,用户需要构建聚合点的 View 才能将数据显示在地图上。

QMUClusterAnnotation点聚合数据类

在<QMapViewDelegate>回调mapView: viewForAnnotation:中可通过判断 annotation 是否为 QMUClusterAnnotation 类进而构建 QMUClusterAnnotationView 类,将数据显示在地图上。

QMUClusterAnnotation 代表了经过聚合计算后的单个聚合点数据,包含了当前范围的所有原始点。有可能有多个原始点,也有可能只有一个。

属性说明:

属性 说明
NSUInteger count 该聚合点包含的原始点个数
NSMutableSet *items 该聚合点包含的所有原始点

QMUClusterAnnotationView点聚合视图

QMUClusterAnnotationView 预定义的聚合点样式 view,一般与QMUClusterAnnotation配套使用。它包含View本身,一个背景图片,一个显示文字,可修改显示效果后直接使用。

属性说明:

属性 说明
UIImageView *background 景图片
UILabel *displayText 显示的文字

构建聚合点 View 的示例:

- (QAnnotationView *)mapView:(QMapView *)mapView viewForAnnotation:(id<QAnnotation>)annotation
{
		// 判断是否为聚合点类  
    if ([annotation isKindOfClass:[QMUClusterAnnotation class]])
    {
        QMUClusterAnnotation* ca = (QMUClusterAnnotation*)annotation;
      
      	// 根据聚合点包含的原始点个数设置样式 view
        if (ca.count > 1) {
            static NSString *clusterReuseIndetifier = @"cluster";
          
            QMUClusterAnnotationView *annotationView = (QMUClusterAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:clusterReuseIndetifier];
            
          	// 样式的背景色
            annotationView.backgroundColor = [UIColor colorWithRed:0.5 green:0.6 blue:0.45 alpha:0.8];
          	// 显示的文字
            annotationView.displayText.text = [[NSNumber numberWithUnsignedInteger:ca.count] stringValue];
            
            if (ca.count >= 100) {
    					......
            }
            else if (ca.count >= 10) {
              ......
            }
            ......
            ......
            return annotationView;
     }
    
    return nil;
}

效果示例图

更详细的设置请参考 demo

这篇文章对您解决问题是否有帮助?

已解决
未解决