本页面介绍了 Maps SDK for iOS 的实用程序库中提供的标记聚类实用程序。
通过将标记聚类,即使在地图上放置大量标记,也不会使地图显得密密麻麻。标记聚类实用程序可帮助您在不同的缩放级别管理多个标记。
当用户以较高的放大倍数查看地图时,地图上会显示每一个具体标记。当用户缩小地图时,这些标记会聚拢形成聚类,以方便用户查看地图。
下面的屏幕截图显示了标记聚类的默认样式:

下面是一个自定义标记聚类的示例:

前提条件和说明
Maps SDK for iOS 实用程序库
标记聚类实用程序包含在 Maps SDK for iOS 实用程序库中。如果您尚未设置该库,请先按照设置指南操作,然后再阅读本页面的其余内容。
为获得最佳性能,建议的最大标记数量为 10,000。
位置信息权限
此示例使用设备的 GPS 在用户坐标上定位用户和地图。如需启用此功能,您必须在项目的 Info.plist
文件中为 NSLocationWhenInUseUsageDescription
权限添加说明。
如需添加,请执行以下操作:
- 点击 Xcode 中项目导航器中的
Info.plist
文件,以打开属性列表编辑器。 - 点击“信息属性列表”旁边的“+”图标以添加新资源。
- 在“key”字段中,输入“NSLocationWhenInUseUsageDescription”。Xcode 会自动将其转换为长名称“Privacy - Location When In Use Description”(隐私 - 使用时的位置说明)。如需查看可能的位置信息权限属性的完整列表,请参阅 Apple 开发者文档中的 请求获取位置信息服务授权。
- 将“类型”字段设置为“字符串”。
- 在“值”字段中,输入应用需要使用用户位置信息的原因的说明。例如,“查找用户以提供附近的商家信息。”
实现标记聚类
实现标记聚类需要执行以下三个步骤:
如需查看有关如何实现标记聚类的完整示例,请参阅 GitHub 上的 Objective-C 和 Swift 示例应用。正在创建集群管理器
如需使用集群管理器,请执行以下操作:
- 设置用于渲染地图的
ViewController
,以符合GMSMapViewDelegate
协议。 - 创建
GMUClusterManager
的实例。 - 将您要实现标记聚类的
GMSMapView
实例和以下协议的实现传递给GMUClusterManager
实例:GMUClusterIconGenerator
:提供应用逻辑,用于提取要在不同缩放级别使用的聚类图标。GMUClusterAlgorithm
:用于指定一种算法,该算法用于确定标记如何聚类的行为,例如同一聚类中所含标记之间的距离。GMUClusterRenderer
:提供用于处理地图上聚类图标实际渲染的应用逻辑。
- 在
GMUClusterManager
实例上设置地图委托。
实用程序库包含图标生成器 (GMUDefaultClusterIconGenerator
)、算法 (GMUNonHierarchicalDistanceBasedAlgorithm
) 和渲染程序 (GMUDefaultClusterRenderer
) 的默认实现。您可以根据需要创建自己的自定义图标生成程序、算法和渲染程序。
以下代码会在 ViewController
的 viewDidLoad
回调中使用这些默认值创建集群管理器:
Swift
import GoogleMaps import GoogleMapsUtils class MarkerClustering: UIViewController, GMSMapViewDelegate { private var mapView: GMSMapView! private var clusterManager: GMUClusterManager! override func viewDidLoad() { super.viewDidLoad() // Set up the cluster manager with the supplied icon generator and // renderer. let iconGenerator = GMUDefaultClusterIconGenerator() let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm() let renderer = GMUDefaultClusterRenderer(mapView: mapView, clusterIconGenerator: iconGenerator) clusterManager = GMUClusterManager(map: mapView, algorithm: algorithm, renderer: renderer) // Register self to listen to GMSMapViewDelegate events. clusterManager.setMapDelegate(self) // ... } // ... }
Objective-C
@import GoogleMaps; @import GoogleMapsUtils; @interface MarkerClustering () <GMSMapViewDelegate> @end @implementation MarkerClustering { GMSMapView *_mapView; GMUClusterManager *_clusterManager; } - (void)viewDidLoad { [super viewDidLoad]; // Set up the cluster manager with a supplied icon generator and renderer. id<GMUClusterAlgorithm> algorithm = [[GMUNonHierarchicalDistanceBasedAlgorithm alloc] init]; id<GMUClusterIconGenerator> iconGenerator = [[GMUDefaultClusterIconGenerator alloc] init]; id<GMUClusterRenderer> renderer = [[GMUDefaultClusterRenderer alloc] initWithMapView:_mapView clusterIconGenerator:iconGenerator]; _clusterManager = [[GMUClusterManager alloc] initWithMap:_mapView algorithm:algorithm renderer:renderer]; // Register self to listen to GMSMapViewDelegate events. [_clusterManager setMapDelegate:self]; // ... } // ... @end
添加标记
您可以通过以下两种方式向标记聚类器添加标记:逐个添加或以数组形式添加。
单个标记
Swift
let position = CLLocationCoordinate2D(latitude: 47.60, longitude: -122.33) let marker = GMSMarker(position: position) clusterManager.add(marker)
Objective-C
CLLocationCoordinate2D position = CLLocationCoordinate2DMake(47.60, -122.33); GMSMarker *marker = [GMSMarker markerWithPosition:position]; [_clusterManager addItem:marker];
标记数组
Swift
let position1 = CLLocationCoordinate2D(latitude: 47.60, longitude: -122.33) let marker1 = GMSMarker(position: position1) let position2 = CLLocationCoordinate2D(latitude: 47.60, longitude: -122.46) let marker2 = GMSMarker(position: position2) let position3 = CLLocationCoordinate2D(latitude: 47.30, longitude: -122.46) let marker3 = GMSMarker(position: position3) let position4 = CLLocationCoordinate2D(latitude: 47.20, longitude: -122.23) let marker4 = GMSMarker(position: position4) let markerArray = [marker1, marker2, marker3, marker4] clusterManager.add(markerArray)
Objective-C
CLLocationCoordinate2D position1 = CLLocationCoordinate2DMake(47.60, -122.33); GMSMarker *marker1 = [GMSMarker markerWithPosition:position1]; CLLocationCoordinate2D position2 = CLLocationCoordinate2DMake(47.60, -122.46); GMSMarker *marker2 = [GMSMarker markerWithPosition:position2]; CLLocationCoordinate2D position3 = CLLocationCoordinate2DMake(47.30, -122.46); GMSMarker *marker3 = [GMSMarker markerWithPosition:position3]; CLLocationCoordinate2D position4 = CLLocationCoordinate2DMake(47.20, -122.23); GMSMarker *marker4 = [GMSMarker markerWithPosition:position4]; NSArray<GMSMarker *> *markerArray = @[marker1, marker2, marker3, marker4]; [_clusterManager addItems:markerArray];
调用标记聚类器
创建标记聚类器并向其传递要聚类的标记后,您只需在标记聚类器实例上调用 cluster
方法即可。
Swift
clusterManager.cluster()
Objective-C
[_clusterManager cluster];
处理标记和聚类上的事件
一般来说,在使用 Maps SDK for iOS 时,如需监听地图上的事件,您必须实现 GMSMapViewDelegate
协议。您可以监听地图事件,但无法监听类型安全的集群管理器事件。当用户点按标记、单个聚类项或聚类时,API 会触发 mapView:didTapMarker:
并将额外的聚类数据附加到 marker.userData
属性。然后,您可以检查 userData
是否符合 GMUCluster
协议,以确定是否点按了聚类图标或标记。
Swift
func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool { // center the map on tapped marker mapView.animate(toLocation: marker.position) // check if a cluster icon was tapped if marker.userData is GMUCluster { // zoom in on tapped cluster mapView.animate(toZoom: mapView.camera.zoom + 1) NSLog("Did tap cluster") return true } NSLog("Did tap a normal marker") return false }
Objective-C
- (BOOL)mapView:(GMSMapView *)mapView didTapMarker:(GMSMarker *)marker { // center the map on tapped marker [_mapView animateToLocation:marker.position]; // check if a cluster icon was tapped if ([marker.userData conformsToProtocol:@protocol(GMUCluster)]) { // zoom in on tapped cluster [_mapView animateToZoom:_mapView.camera.zoom + 1]; NSLog(@"Did tap cluster"); return YES; } NSLog(@"Did tap marker in cluster"); return NO; }
现在,集群管理器会拦截您在 clusterManager
上实现的任何事件。它会将所有剩余的事件转发给地图委托(如果提供)。请注意,标准标记的事件(即,不是由聚类渲染器生成的标记)始终转发到地图委托。
自定义标记聚类
您可以为 GMUClusterRenderer
、GMUClusterIconGenerator
或 GMUClusterAlgorithm
提供自定义实现。您可以基于实用程序库中包含的这些协议的示例实现来创建自定义实现,也可以通过执行相应协议来编写完全自定义的实现。