Utilidad del agrupamiento de marcadores en clústeres para Google Maps en Android

Al agrupar tus marcadores en clústeres, puedes incluir muchos marcadores en un mapa sin que esto dificulte su lectura.

Introducción

En este video, se trata el uso del agrupamiento de marcadores en clústeres cuando tus datos requieren una gran cantidad de puntos de datos en el mapa.

La utilidad del agrupamiento de marcadores en clústeres te permite administrar varios marcadores con diferentes niveles de zoom. Para ser precisos, los "marcadores" en realidad son "elementos" en este punto y solo se convierten en "marcadores" al renderizarse. No obstante, a fin de garantizar una mayor claridad, se usará la denominación "marcador" en todo el documento.

Cuando un usuario visualiza el mapa con un alto nivel de zoom, aparecen los marcadores individuales. Cuando el usuario aleja el mapa, los marcadores se agrupan en clústeres para facilitar su visualización. La utilidad del agrupamiento de marcadores en clústeres forma parte de la biblioteca de utilidades del SDK de Maps para Android. Si aún no configuraste la biblioteca, sigue la guía de configuración antes de leer el resto de esta página.

Mapa con marcadores agrupados en clústeres
Marcadores agrupados en clústeres

Para usar la utilidad del agrupamiento de marcadores en clústeres, deberás agregar marcadores como objetos ClusterItem a ClusterManager. ClusterManager pasa los marcadores a Algorithm y este los transforma en un conjunto de clústeres. ClusterRenderer se encarga de la renderización. Para hacerlo, agrega y quita clústeres y marcadores individuales. ClusterRenderer y Algorithm son acoplables y se pueden personalizar.

En la biblioteca de utilidades se incluye una app de demostración en la que se ofrecen ejemplos de implementaciones de la utilidad de agrupamiento de marcadores en clústeres. Para obtener ayuda con la ejecución de la app de demostración, consulta la guía de configuración. En la app de demostración se incluyen los siguientes ejemplos de agrupamientos de marcadores en clústeres:

  • ClusteringDemoActivity: una actividad simple en la que se muestra el agrupamiento de marcadores en clústeres
  • BigClusteringDemoActivity: agrupamiento en clústeres de 2,000 marcadores
  • CustomMarkerClusteringDemoActivity: creación de un diseño personalizado para los marcadores agrupados en clústeres

Cómo agregar un clúster de marcadores simple

Sigue los pasos que aparecen a continuación para crear un clúster simple de diez marcadores. El resultado tendrá el siguiente aspecto, aunque el número de marcadores que se muestren o aparezcan agrupados en clúster cambiará según el nivel de zoom:

Mapa con diez marcadores agrupados en clústeres
Diez marcadores agrupados en clústeres

A continuación, encontrarás un resumen de los pasos que deben seguirse:

  1. Implementa ClusterItem para representar un marcador en el mapa. El elemento de clúster muestra la posición del marcador como un objeto LatLng y un título o un fragmento opcionales.
  2. Agrega un objeto ClusterManager nuevo para agrupar los elementos del clúster (marcadores) en función del nivel de zoom.
  3. Configura el método OnCameraIdleListener() del mapa en ClusterManager, ya que ClusterManager implementa el objeto de escucha.
  4. Si deseas agregar funcionalidades específicas en respuesta a un evento de clic de marcador, configura el método OnMarkerClickListener() del mapa en ClusterManager, ya que ClusterManager implementa el objeto de escucha.
  5. Ingresa los marcadores en ClusterManager.

Una vista detallada de los pasos: Para crear el clúster simple de diez marcadores, primero crea una clase MyItem con la que se implemente ClusterItem.

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
    }
}
      

En tu actividad en Maps, agrega ClusterManager y transmítele los elementos del clúster. Considera el argumento de tipo <MyItem>, que declara que ClusterManager corresponde al tipo 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)
    }
}
      

También puedes inhabilitar las animaciones de agrupamiento en clústeres cuando acercas o alejas el mapa. Si la animación está desactivada, los marcadores se ubican en su posición en lugar de migrar desde y hacia los clústeres. Para inhabilitar las animaciones, usa setAnimation() en ClusterManager como se muestra a continuación:

Java

clusterManager.setAnimation(false);
      

Kotlin

clusterManager.setAnimation(false)
      

Cómo agregar una ventana de información para un marcador agrupado en clúster individual

A fin de agregar una ventana de información para marcadores agrupados en clústeres específicos, agrega strings de título y fragmento al constructor de tu implementación de ClusterItem.

En el siguiente ejemplo, se agrega un marcador con una ventana de información en el método addItems() mediante la configuración de un título y un fragmento:

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)
      

Cómo personalizar los clústeres de marcadores

El constructor de ClusterManager crea DefaultClusterRenderer y NonHierarchicalDistanceBasedAlgorithm. Puedes cambiar ClusterRenderer y Algorithm con los métodos setAlgorithm(Algorithm<T> algorithm) y setRenderer(ClusterRenderer<T> view) de ClusterManager.

Puedes implementar ClusterRenderer para personalizar la renderización de los clústeres. DefaultClusterRenderer proporciona una buena base como punto de partida. Puedes subclasificar DefaultClusterRenderer para anular los valores predeterminados.

Para ver un ejemplo exhaustivo de la personalización, consulta CustomMarkerClusteringDemoActivity en la app de demostración que se incluye en la biblioteca de utilidades.

Mapa con marcadores agrupados en clústeres personalizados
Marcadores agrupados en clústeres personalizados

CustomMarkerClusteringDemoActivity define su propio elemento de clúster, Person, y lo renderiza extendiendo DefaultClusterRenderer como PersonRenderer.

La demostración también muestra cómo implementar la interfaz ClusterManager.OnClusterClickListener<Person> para mostrar más información sobre la persona cuando se hace clic en el clúster. También puedes implementar ClusterManager.OnClusterItemClickListener<Person> de manera similar.

Para obtener ayuda con la ejecución de la app de demostración, consulta la guía de configuración.