Utilitário de clustering de marcadores do Google Maps para Android

O clustering de marcadores permite colocar um grande número de marcadores em um mapa sem dificultar a leitura.

Introdução

Este vídeo discute o uso de clustering de marcadores como uma alternativa aos marcadores quando os dados exigem um grande número de pontos de dados no mapa.

O utilitário de clustering de marcadores ajuda a gerenciar vários marcadores em diferentes níveis de zoom. Na verdade, os "marcadores" são "itens" neste ponto e somente se tornam "marcadores" quando são renderizados. No entanto, para maior clareza, este documento usará sempre o termo "marcadores".

Quando um usuário visualiza um mapa em um nível de zoom alto, os marcadores individuais são exibidos no mapa. Quando o usuário diminui o zoom, os marcadores se reúnem em clusters, facilitando a visualização. O utilitário de clustering de marcadores faz parte da Biblioteca de utilitários do SDK do Maps para Android. Se você ainda não configurou a biblioteca, siga o guia antes de ler o restante desta página.

Mapa com marcadores em cluster
Marcadores em cluster

Para usar o utilitário de clustering de marcadores, é necessário adicionar os marcadores como objetos ClusterItem ao ClusterManager. A classe ClusterManager transmite os marcadores para Algorithm, que os transforma em um conjunto de clusters. ClusterRenderer é responsável pela renderização, adicionando e removendo clusters e marcadores individuais. ClusterRenderer e Algorithm são conectáveis e podem ser personalizados.

A biblioteca de utilitários é fornecida com um app de demonstração, que oferece implementações de exemplo do utilitário de clustering de marcadores. Para receber ajuda com a execução do app de demonstração, consulte o guia de configuração. O app de demonstração inclui os seguintes exemplos de clustering de marcadores:

  • ClusteringDemoActivity: uma atividade simples demonstrando o clustering de marcadores.
  • BigClusteringDemoActivity: clustering com 2.000 marcadores.
  • CustomMarkerClusteringDemoActivity: criação de um projeto personalizado para marcadores em cluster.

Adicionar um clusterer de marcadores simples

Siga estas etapas para criar um cluster simples de dez marcadores. O resultado será semelhante ao mostrado a seguir, embora o número de marcadores mostrados/em cluster mude em função do nível de zoom:

Mapa com dez marcadores em cluster
Dez marcadores em cluster

Veja a seguir um resumo das etapas necessárias:

  1. Implemente ClusterItem para representar um marcador no mapa. O item de cluster retorna a posição do marcador como um objeto LatLng e um título ou snippet opcional.
  2. Adicione um novo ClusterManager para agrupar os itens de cluster (marcadores) de acordo com o nível de zoom.
  3. Defina o evento OnCameraIdleListener() do mapa como ClusterManager, já que ClusterManager implementa o listener.
  4. Se você quiser adicionar uma funcionalidade específica em resposta a um evento de clique de marcador, defina o evento OnMarkerClickListener() do mapa como ClusterManager, já que ClusterManager implementa o listener.
  5. Alimente os marcadores no ClusterManager.

Aprofundando as etapas: para criar nosso cluster simples com dez marcadores, primeiro crie uma classe MyItem que 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
    }
}
      

Na atividade do mapa, adicione ClusterManager e alimente os itens do cluster. Observe o argumento de tipo <MyItem>, que declara ClusterManager como sendo do 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)
    }
}
      

Também é possível desativar as animações de clustering ao aumentar e diminuir o zoom. Se a animação estiver desativada, os marcadores serão colocados em uma posição, em vez de migrar dos clusters. Para desativar as animações, use setAnimation() em ClusterManager, como abaixo:

Java

clusterManager.setAnimation(false);
      

Kotlin

clusterManager.setAnimation(false)
      

Adicionar uma janela de informações para um marcador em cluster individual

Para adicionar uma janela de informações a marcadores em cluster específicos, inclua strings de título e snippet ao construtor da implementação de ClusterItem.

O exemplo a seguir adiciona um marcador com uma janela de informações no método addItems(), definindo um título e snippet:

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)
      

Personalizar os clusters de marcadores

O construtor ClusterManager cria um DefaultClusterRenderer e um NonHierarchicalDistanceBasedAlgorithm. É possível alterar ClusterRenderer e Algorithm usando os métodos setAlgorithm(Algorithm<T> algorithm) e setRenderer(ClusterRenderer<T> view) de ClusterManager.

Você pode implementar ClusterRenderer para personalizar a renderização dos clusters. DefaultClusterRenderer fornece uma boa base para começar. Defina DefaultClusterRenderer como subclasse para modificar os padrões.

Para ver um exemplo detalhado de personalização, consulte CustomMarkerClusteringDemoActivity no app de demonstração que acompanha a biblioteca de utilitários.

Mapa com marcadores em cluster personalizados
Marcadores em cluster personalizados

CustomMarkerClusteringDemoActivity define o próprio item de cluster, um Person, e o renderiza ao estender DefaultClusterRenderer como PersonRenderer.

A demonstração também mostra como implementar a interface ClusterManager.OnClusterClickListener<Person> para exibir mais informações sobre a pessoa quando o cluster é clicado. Também é possível implementar ClusterManager.OnClusterItemClickListener<Person> de maneira semelhante.

Para receber ajuda com a execução do app de demonstração, consulte o guia de configuração.