Google Maps Android 标记聚类实用程序

通过将标记聚类,即使在地图上放置大量标记,也不会使地图变得难以查看。

简介

这段视频介绍了如何在您的数据要求地图上包含大量数据点时使用标记聚类。

标记聚类实用程序可帮助您管理不同缩放级别的多个标记。确切地讲,此时的“标记”实际上只是“项”,只有在被渲染时才会变为“标记”。但是为清楚起见,本文全篇均将其称作“标记”。

当用户在高缩放级别下查看地图时,各个标记会显示在地图上。当用户缩小时,这些标记会聚拢形成聚类,以方便用户查看地图。标记聚类实用程序是 Maps SDK for Android 实用程序库的一部分。如果您尚未设置该库,请按照设置指南操作,然后再阅读本页面的其余内容。

一幅包含聚类标记的地图
聚类标记

如需使用标记聚类实用程序,您需要将标记作为 ClusterItem 对象添加到 ClusterManagerClusterManager 会将标记传递给 Algorithm,后者将它们转变成一组聚类。ClusterRenderer 通过添加和移除聚类和个别标记进行渲染。ClusterRendererAlgorithm 是可以插入的,并可进行自定义。

实用程序库自带一个演示版应用,提供了标记聚类实用程序的示例实现。如需有关运行演示版应用的帮助,请参阅设置指南。演示版应用包括下列标记聚类示例:

  • ClusteringDemoActivity:一个演示标记聚类的简单 Activity。
  • BigClusteringDemoActivity:包含 2000 个标记的聚类。
  • CustomMarkerClusteringDemoActivity:为聚类标记创建自定义设计。

添加简单的标记聚类器

按以下步骤创建一个包含十个标记的简单聚类。结果与下图类似,但显示/聚类的标记数量将随缩放级别发生变化:

一幅包含十个聚类标记的地图
十个聚类标记

下面概要列出了所需步骤:

  1. 实现 ClusterItem 以表示地图上的标记。聚类项返回 LatLng 对象形式的标记位置,以及可选标题或信息摘要。
  2. 新增一个 ClusterManager,以根据缩放级别对聚类项(标记)进行分组。
  3. 将地图的 OnCameraIdleListener() 设置为 ClusterManager,因为 ClusterManager 会实现监听器。
  4. 如果您想添加特定功能来响应标记点击事件,请将地图的 OnMarkerClickListener() 设置为 ClusterManager,因为 ClusterManager 会实现监听器。
  5. 将标记送入 ClusterManager

以下列出了更详细的步骤:要创建包含十个标记的简单聚类,请先创建可实现 ClusterItemMyItem 类。

Java

public class MyItem implements ClusterItem {
    private final LatLng position;
    private final String title;
    private final String snippet;

    public MyItem(double lat, double lng, String title, String snippet) {
        position = new LatLng(lat, lng);
        this.title = title;
        this.snippet = snippet;
    }

    @Override
    public LatLng getPosition() {
        return position;
    }

    @Override
    public String getTitle() {
        return title;
    }

    @Override
    public String getSnippet() {
        return snippet;
    }
}
      

Kotlin

inner class MyItem(
    lat: Double,
    lng: Double,
    title: String,
    snippet: String
) : ClusterItem {

    private val position: LatLng
    private val title: String
    private val snippet: String

    override fun getPosition(): LatLng {
        return position
    }

    override fun getTitle(): String? {
        return title
    }

    override fun getSnippet(): String? {
        return snippet
    }

    init {
        position = LatLng(lat, lng)
        this.title = title
        this.snippet = snippet
    }
}
      

在您的地图 activity 中,添加 ClusterManager 并向其提供聚类项。请注意将 ClusterManager 声明为 MyItem 类型的类型参数 <MyItem>

Java

// Declare a variable for the cluster manager.
private ClusterManager<MyItem> clusterManager;

private void setUpClusterer() {
    // Position the map.
    map.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(51.503186, -0.126446), 10));

    // Initialize the manager with the context and the map.
    // (Activity extends context, so we can pass 'this' in the constructor.)
    clusterManager = new ClusterManager<MyItem>(context, map);

    // Point the map's listeners at the listeners implemented by the cluster
    // manager.
    map.setOnCameraIdleListener(clusterManager);
    map.setOnMarkerClickListener(clusterManager);

    // Add cluster items (markers) to the cluster manager.
    addItems();
}

private void addItems() {

    // Set some lat/lng coordinates to start with.
    double lat = 51.5145160;
    double lng = -0.1270060;

    // Add ten cluster items in close proximity, for purposes of this example.
    for (int i = 0; i < 10; i++) {
        double offset = i / 60d;
        lat = lat + offset;
        lng = lng + offset;
        MyItem offsetItem = new MyItem(lat, lng, "Title " + i, "Snippet " + i);
        clusterManager.addItem(offsetItem);
    }
}
      

Kotlin

// Declare a variable for the cluster manager.
private lateinit var clusterManager: ClusterManager<MyItem>

private fun setUpClusterer() {
    // Position the map.
    map.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(51.503186, -0.126446), 10f))

    // Initialize the manager with the context and the map.
    // (Activity extends context, so we can pass 'this' in the constructor.)
    clusterManager = ClusterManager(context, map)

    // Point the map's listeners at the listeners implemented by the cluster
    // manager.
    map.setOnCameraIdleListener(clusterManager)
    map.setOnMarkerClickListener(clusterManager)

    // Add cluster items (markers) to the cluster manager.
    addItems()
}

private fun addItems() {

    // Set some lat/lng coordinates to start with.
    var lat = 51.5145160
    var lng = -0.1270060

    // Add ten cluster items in close proximity, for purposes of this example.
    for (i in 0..9) {
        val offset = i / 60.0
        lat += offset
        lng += offset
        val offsetItem =
            MyItem(lat, lng, "Title $i", "Snippet $i")
        clusterManager.addItem(offsetItem)
    }
}
      

您还可以选择在缩放时停用聚类动画。如果动画已关闭,则标记会直接跳至对应位置,而不会显示移出和移入聚类的过程。 要停用动画,请在 ClusterManager 中使用 setAnimation(),如下所示:

Java

clusterManager.setAnimation(false);
      

Kotlin

clusterManager.setAnimation(false)
      

为个别聚类标记添加信息窗口

要为特定聚类标记添加信息窗口,请在 ClusterItem 实现的构造函数中添加标题和信息摘要字符串。

以下示例通过设置标题和信息摘要,使用 addItems() 方法添加了一个含信息窗口的标记:

Java

// Set the lat/long coordinates for the marker.
double lat = 51.5009;
double lng = -0.122;

// Set the title and snippet strings.
String title = "This is the title";
String snippet = "and this is the snippet.";

// Create a cluster item for the marker and set the title and snippet using the constructor.
MyItem infoWindowItem = new MyItem(lat, lng, title, snippet);

// Add the cluster item (marker) to the cluster manager.
clusterManager.addItem(infoWindowItem);
      

Kotlin

// Set the lat/long coordinates for the marker.
val lat = 51.5009
val lng = -0.122

// Set the title and snippet strings.
val title = "This is the title"
val snippet = "and this is the snippet."

// Create a cluster item for the marker and set the title and snippet using the constructor.
val infoWindowItem = MyItem(lat, lng, title, snippet)

// Add the cluster item (marker) to the cluster manager.
clusterManager.addItem(infoWindowItem)
      

自定义标记聚类

ClusterManager 构造函数会创建一个 DefaultClusterRendererNonHierarchicalDistanceBasedAlgorithm。您可以使用 ClusterManagersetAlgorithm(Algorithm<T> algorithm)setRenderer(ClusterRenderer<T> view) 方法更改 ClusterRendererAlgorithm

您可以通过实现 ClusterRenderer 来自定义聚类的渲染。DefaultClusterRenderer 提供了一个很好的基础作为入手点。您可以通过为 DefaultClusterRenderer 创建子类来重写默认值。

如需查看深入的自定义示例,请看一看实用程序库附带的演示版应用中的 CustomMarkerClusteringDemoActivity

一幅包含自定义聚类标记的地图
自定义聚类标记

CustomMarkerClusteringDemoActivity 定义了自己的聚类项 Person,并通过将 DefaultClusterRenderer 扩展为 PersonRenderer 进行渲染。

该演示还展示了如何实现 ClusterManager.OnClusterClickListener<Person> 接口,以在有人点击聚类时显示相关人员的详细信息。您还可以通过类似方式实现 ClusterManager.OnClusterItemClickListener<Person>

如需有关运行演示版应用的帮助,请参阅设置指南