Formas

A API Google Maps para Android oferece algumas maneiras simples de adicionar formas a mapas para personalizá-los de acordo com seu app.

  • Polyline é uma série de segmentos de linha conectados que pode criar qualquer forma para marcar caminhos e trajetos no mapa.
  • Polygon é uma forma delimitada que pode ser usada para marcar áreas no mapa.
  • Circle é uma projeção geograficamente precisa de um círculo na superfície do planeta no mapa.

Para todas essas formas, você pode personalizar sua aparência, alterando diversas propriedades.

Exemplos de código

O tutorial sobre como adicionar polígonos e polilinhas para representar áreas e trajetos inclui todo o código de um app Android simples.

Além disso, o repositório ApiDemos no GitHub inclui exemplos que demonstram o uso de formas e os respectivos recursos:

Polilinhas

A classe Polyline define um conjunto de segmentos de linha conectados no mapa. Um objeto Polyline é composto por um conjunto de locais LatLng e cria uma série de segmentos de linha que conectam esses locais em uma sequência ordenada.

Neste vídeo, mostramos como ajudar os usuários a chegar ao destino, usando polilinhas para desenhar um caminho no mapa.

Para criar uma polilinha, primeiro crie um objeto PolylineOptions e adicione pontos a ele. Os pontos representam um ponto na superfície terrestre e são expressos como um objeto LatLng. Segmentos de linha são desenhados entre pontos, de acordo com a ordem em que você os adiciona ao objeto PolylineOptions. Para adicionar pontos a um objeto PolylineOptions, chame PolylineOptions.add(). Esse método tem um número variável de parâmetros para permitir a adição de vários pontos de uma vez. Também é possível chamar PolylineOptions.addAll(Iterable<LatLng>) quando os pontos já estão em uma lista.

Você pode adicionar a polilinha a um mapa chamando GoogleMap.addPolyline(PolylineOptions). O método retorna um objeto Polyline que você pode usar para alterar a polilinha mais tarde.

O fragmento de código a seguir demonstra como adicionar um retângulo a um mapa:

Java

// Instantiates a new Polyline object and adds points to define a rectangle
PolylineOptions polylineOptions = new PolylineOptions()
    .add(new LatLng(37.35, -122.0))
    .add(new LatLng(37.45, -122.0))  // North of the previous point, but at the same longitude
    .add(new LatLng(37.45, -122.2))  // Same latitude, and 30km to the west
    .add(new LatLng(37.35, -122.2))  // Same longitude, and 16km to the south
    .add(new LatLng(37.35, -122.0)); // Closes the polyline.

// Get back the mutable Polyline
Polyline polyline = map.addPolyline(polylineOptions);
      

Kotlin

// Instantiates a new Polyline object and adds points to define a rectangle
val polylineOptions = PolylineOptions()
    .add(LatLng(37.35, -122.0))
    .add(LatLng(37.45, -122.0)) // North of the previous point, but at the same longitude
    .add(LatLng(37.45, -122.2)) // Same latitude, and 30km to the west
    .add(LatLng(37.35, -122.2)) // Same longitude, and 16km to the south
    .add(LatLng(37.35, -122.0)) // Closes the polyline.

// Get back the mutable Polyline
val polyline = map.addPolyline(polylineOptions)
      

Para mudar a forma da polilinha depois de adicioná-la, chame Polyline.setPoints() e forneça uma nova lista de pontos para a polilinha.

Você pode personalizar a aparência da polilinha antes e depois de incluí-la no mapa. Consulte a seção sobre como personalizar aparências abaixo para ver mais detalhes.

Eventos de polilinha

Por padrão, as polilinhas não são clicáveis. Para ativar e desativar essa função, chame Polyline.setClickable(boolean).

Use um OnPolylineClickListener para detectar os eventos de clique em uma polilinha clicável. Se quiser definir esse listener no mapa, chame GoogleMap.setOnPolylineClickListener(OnPolylineClickListener). Quando um usuário clicar em uma polilinha, você receberá um callback onPolylineClick(Polyline).

Polígonos

Os objetos Polygon são parecidos com os objetos Polyline, porque são formados por uma série de coordenadas em uma sequência ordenada. No entanto, em vez de serem abertos, os polígonos foram desenvolvidos para definir regiões dentro de um loop fechado com o interior preenchido.

Você pode adicionar um Polygon ao mapa da mesma forma que adiciona uma Polyline. Primeiro crie um objeto PolygonOptions e adicione alguns pontos a ele. Esses pontos formam o contorno do polígono. Depois, adicione o polígono ao mapa chamando GoogleMap.addPolygon(PolygonOptions), que retornará um objeto Polygon.

O snippet de código a seguir adiciona um retângulo a um mapa. Como não definimos uma cor de preenchimento, e a padrão é transparente, ele terá exatamente a mesma aparência da polilinha do snippet da seção anterior:

Java

// Instantiates a new Polygon object and adds points to define a rectangle
PolygonOptions polygonOptions = new PolygonOptions()
    .add(new LatLng(37.35, -122.0),
        new LatLng(37.45, -122.0),
        new LatLng(37.45, -122.2),
        new LatLng(37.35, -122.2),
        new LatLng(37.35, -122.0));

// Get back the mutable Polygon
Polygon polygon = map.addPolygon(polygonOptions);
      

Kotlin

// Instantiates a new Polygon object and adds points to define a rectangle
val rectOptions = PolygonOptions()
    .add(
        LatLng(37.35, -122.0),
        LatLng(37.45, -122.0),
        LatLng(37.45, -122.2),
        LatLng(37.35, -122.2),
        LatLng(37.35, -122.0)
    )

// Get back the mutable Polygon
val polygon = map.addPolygon(rectOptions)
      

Para mudar a forma do polígono depois de adicioná-lo, chame Polygon.setPoints() e forneça uma nova lista de pontos para o contorno do polígono.

Você pode personalizar a aparência do polígono antes e depois de incluí-lo no mapa. Consulte a seção sobre como personalizar aparências abaixo para ver mais detalhes.

Preenchimento automático de polígonos

O polígono do exemplo acima consiste em cinco coordenadas. A primeira e a última coordenada estão no mesmo local, definindo o loop. No entanto, na prática, como os polígonos definem áreas fechadas, não é necessário definir a última coordenada. Se a última coordenada for diferente da primeira, a API "fechará" automaticamente o polígono, anexando a primeira coordenada a fim da sequência de coordenadas.

Os dois polígonos abaixo são equivalentes, e chamar polygon.getPoints() para cada um deles retornará todos os quatro pontos.

Java

Polygon polygon1 = map.addPolygon(new PolygonOptions()
    .add(new LatLng(0, 0),
        new LatLng(0, 5),
        new LatLng(3, 5),
        new LatLng(0, 0))
    .strokeColor(Color.RED)
    .fillColor(Color.BLUE));

Polygon polygon2 = map.addPolygon(new PolygonOptions()
    .add(new LatLng(0, 0),
        new LatLng(0, 5),
        new LatLng(3, 5))
    .strokeColor(Color.RED)
    .fillColor(Color.BLUE));
      

Kotlin

val polygon1 = map.addPolygon(
    PolygonOptions()
        .add(
            LatLng(0.0, 0.0),
            LatLng(0.0, 5.0),
            LatLng(3.0, 5.0),
            LatLng(0.0, 0.0)
        )
        .strokeColor(Color.RED)
        .fillColor(Color.BLUE)
)
val polygon2 = map.addPolygon(
    PolygonOptions()
        .add(
            LatLng(0.0, 0.0),
            LatLng(0.0, 5.0),
            LatLng(3.0, 5.0)
        )
        .strokeColor(Color.RED)
        .fillColor(Color.BLUE)
)
      

Criar um polígono oco

Vários caminhos podem ser combinados em um único objeto Polygon para criar formas complexas, como anéis preenchidos, ou "roscas", em que as áreas poligonais aparecem dentro do polígono como "ilhas". Formas complexas são sempre a composição de vários caminhos mais simples.

É necessário definir dois caminhos na mesma área. A maior das duas regiões define a área de preenchimento e é um polígono simples, sem opções adicionais. Depois, chame um segundo caminho para o método addHole(). Quando o segundo caminho menor for fechado totalmente pelo maior, parecerá que um pedaço do polígono foi removido. Se o buraco cruzar o contorno do polígono, o polígono será renderizado sem nenhum preenchimento.

O snippet a seguir cria um único retângulo, com um buraco retangular menor.

Java

List<LatLng> hole = Arrays.asList(new LatLng(1, 1),
    new LatLng(1, 2),
    new LatLng(2, 2),
    new LatLng(2, 1),
    new LatLng(1, 1));
Polygon hollowPolygon = map.addPolygon(new PolygonOptions()
    .add(new LatLng(0, 0),
        new LatLng(0, 5),
        new LatLng(3, 5),
        new LatLng(3, 0),
        new LatLng(0, 0))
    .addHole(hole)
    .fillColor(Color.BLUE));
      

Kotlin

val hole = listOf(
    LatLng(1.0, 1.0),
    LatLng(1.0, 2.0),
    LatLng(2.0, 2.0),
    LatLng(2.0, 1.0),
    LatLng(1.0, 1.0)
)
val hollowPolygon = map.addPolygon(
    PolygonOptions()
        .add(
            LatLng(0.0, 0.0),
            LatLng(0.0, 5.0),
            LatLng(3.0, 5.0),
            LatLng(3.0, 0.0),
            LatLng(0.0, 0.0)
        )
        .addHole(hole)
        .fillColor(Color.BLUE)
)
      

Eventos de polígono

Por padrão, os polígonos não são clicáveis. Para ativar e desativar essa função, chame Polygon.setClickable(boolean).

Use um OnPolygonClickListener para detectar os eventos de clique em um polígono clicável. Se quiser definir esse listener no mapa, chame GoogleMap.setOnPolygonClickListener(OnPolygonClickListener). Quando um usuário clicar em um polígono, você receberá um callback onPolygonClick(Polygon).

Círculos

Além de uma classe Polygon genérica, a API Maps também inclui classes específicas para objetos Circle para simplificar a construção.

Para construir um círculo, é preciso especificar estas duas propriedades:

  • center como LatLng
  • radius em metros

Um círculo é, então, definido como sendo o conjunto de todos os pontos da superfície terrestre que ficam a radius metros de distância do center especificado. Devido à forma como a projeção Mercator usada pela API Maps renderiza uma esfera em uma superfície plana, o círculo exibido será praticamente perfeito no mapa, quando localizado perto da Linha do Equador, e será cada vez menos circular à medida que se afastar da linha.

O snippet de código a seguir adiciona um círculo ao mapa, construindo um objeto CircleOptions e chamando GoogleMap.addCircle(CircleOptions):

Java

// Instantiates a new CircleOptions object and defines the center and radius
CircleOptions circleOptions = new CircleOptions()
    .center(new LatLng(37.4, -122.1))
    .radius(1000); // In meters

// Get back the mutable Circle
Circle circle = map.addCircle(circleOptions);
      

Kotlin

// Instantiates a new CircleOptions object and defines the center and radius
val circleOptions = CircleOptions()
    .center(LatLng(37.4, -122.1))
    .radius(1000.0) // In meters

// Get back the mutable Circle
val circle = map.addCircle(circleOptions)
      

Para mudar a forma do círculo depois de adicioná-lo, chame Circle.setRadius() ou Circle.setCenter() e informe os novos valores.

Você pode personalizar a aparência do círculo antes e depois de incluí-lo no mapa. Consulte a seção sobre como personalizar aparências abaixo para ver mais detalhes.

Eventos de círculo

Por padrão, os círculos não são clicáveis. Para ativar e desativar essa função, chame GoogleMap.addCircle() com CircleOptions.clickable(boolean) ou Circle.setClickable(boolean).

Use um OnCircleClickListener para detectar eventos de clique em um círculo clicável. Se quiser definir esse listener no mapa, chame GoogleMap.setOnCircleClickListener(OnCircleClickListener).

Quando um usuário clicar em um círculo, você receberá um callback onCircleClick(Circle), conforme mostrado no exemplo de código a seguir:

Java

Circle circle = map.addCircle(new CircleOptions()
    .center(new LatLng(37.4, -122.1))
    .radius(1000)
    .strokeWidth(10)
    .strokeColor(Color.GREEN)
    .fillColor(Color.argb(128, 255, 0, 0))
    .clickable(true));

map.setOnCircleClickListener(new GoogleMap.OnCircleClickListener() {
    @Override
    public void onCircleClick(Circle circle) {
        // Flip the r, g and b components of the circle's stroke color.
        int strokeColor = circle.getStrokeColor() ^ 0x00ffffff;
        circle.setStrokeColor(strokeColor);
    }
});
      

Kotlin

val circle = map.addCircle(
    CircleOptions()
        .center(LatLng(37.4, -122.1))
        .radius(1000.0)
        .strokeWidth(10f)
        .strokeColor(Color.GREEN)
        .fillColor(Color.argb(128, 255, 0, 0))
        .clickable(true)
)
map.setOnCircleClickListener {
    // Flip the r, g and b components of the circle's stroke color.
    val strokeColor = it.strokeColor xor 0x00ffffff
    it.strokeColor = strokeColor
}
      

Como personalizar aparências

É possível alterar a aparência de uma forma antes de adicioná-la ao mapa, especificando a propriedade desejada no objeto de opções, ou depois. Getters também são expostos para todas as propriedades, assim, você pode acessar facilmente o estado atual da forma.

O snippet a seguir adiciona um polígono azul espesso com segmentos geodésicos de Melbourne a Perth. As seções abaixo explicam essas propriedades com mais detalhes.

Java

Polyline polyline = map.addPolyline(new PolylineOptions()
    .add(new LatLng(-37.81319, 144.96298), new LatLng(-31.95285, 115.85734))
    .width(25)
    .color(Color.BLUE)
    .geodesic(true));
      

Kotlin

val polyline = map.addPolyline(
    PolylineOptions()
        .add(LatLng(-37.81319, 144.96298), LatLng(-31.95285, 115.85734))
        .width(25f)
        .color(Color.BLUE)
        .geodesic(true)
)
      

Observação: mesmo que a maior parte delas possa ser aplicada a qualquer uma das formas descritas, algumas propriedades não fazem sentido para determinadas formas, por exemplo, uma polilinha não pode ter uma cor de preenchimento porque não tem um interior.

Cor do traço

A cor do traço é um número inteiro alfa-vermelho-verde-azul (ARGB) de 32 bits que especifica a opacidade e a cor do traço da forma. Defina essa propriedade no objeto de opções da forma chamando *Options.strokeColor(), ou PolylineOptions.color() no caso de uma polilinha. Se não for especificada, a cor do traço padrão será preto (Color.BLACK).

Após a forma ser adicionada ao mapa, a cor do traço pode ser acessada chamando getStrokeColor() (ou getColor() para uma polilinha) e pode ser alterada chamando setStrokeColor() (setColor() for a polyline).

Cor de preenchimento

A cor de preenchimento só se aplica a polígonos e círculos, e não a polilinhas, porque elas não têm interiores definidos. Para um polígono, as regiões no interior dos orifícios não fazem parte do interior do polígono e não são coloridas se uma cor de preenchimento é definida.

A cor de preenchimento é um número inteiro alfa-vermelho-verde-azul (ARGB) de 32 bits que especifica a opacidade e a cor do interior da forma. Defina essa propriedade no objeto de opções da forma chamando *Options.fillColor(). Se não for especificada, a cor do traço padrão será transparente (Color.TRANSPARENT).

Após a forma ser adicionada ao mapa, a cor de preenchimento pode ser acessada chamando getFillColor() e pode ser alterada chamando setFillColor().

Largura do traço

A largura do traço da linha, como um ponto flutuante em pixels (px). A largura não é dimensionada quando o mapa é ampliado (ou seja, uma forma terá a mesma largura de traço em todos os níveis de zoom). Defina essa propriedade no objeto de opção da forma chamando *Options.strokeWidth() (ou PolylineOptions.width() para uma polilinha). Se não especificada, a largura do traço padrão é 10 pixels.

Após a forma ser adicionada ao mapa, a largura do traço pode ser acessada chamando getStrokeWidth() (ou getWidth() para uma polilinha) e pode ser alterada chamando setStrokeWidth() (setWidth() for a polyline).

Padrão de traço

O tipo do traço padrão é uma linha sólida para polilinhas e contornos de polígonos e círculos. É possível especificar um padrão de traço personalizado dos objetos PatternItem, em que cada item é um traço, um ponto ou uma lacuna.

O exemplo a seguir define o padrão de uma polilinha como uma sequência repetida de um ponto, seguido por uma lacuna de comprimento de 20 pixels, um traço de 30 pixels e outra lacuna de 20 pixels.

Java

List<PatternItem> pattern = Arrays.asList(
    new Dot(), new Gap(20), new Dash(30), new Gap(20));
polyline.setPattern(pattern);
      

Kotlin

val pattern = listOf(
    Dot(), Gap(20F), Dash(30F), Gap(20F)
)
polyline.pattern = pattern
      

O padrão se repete ao longo da linha, começando com o primeiro item de padrão no primeiro vértice especificado para a forma.

Tipos de junção

Em polilinhas e contornos de polígonos, você pode especificar um JointType circular ou chanfrado para substituir as junções fixas padrão.

O exemplo a seguir aplica um tipo de junção circular para uma polilinha:

Java

polyline.setJointType(JointType.ROUND);
      

Kotlin

polyline.jointType = JointType.ROUND
      

O tipo de junção afeta as dobras internas na linha. Se a linha tiver um padrão de traço que inclui traços, o tipo de junção também será aplicado quando um traço também abranger uma junção. Os tipos de junção não afetam os pontos, porque eles são sempre circulares.

Limites de linha

Você pode especificar um estilo Cap para cada extremidade de uma polilinha. As opções são nó (padrão), quadrado, redondo ou um bitmap personalizado. Defina o estilo em PolylineOptions.startCap e PolylineOptions.endCap ou use os métodos getter e setter apropriados.

O snippet a seguir especifica um limite circular no início de uma polilinha.

Java

polyline.setStartCap(new RoundCap());
      

Kotlin

polyline.startCap = RoundCap()
      

O snippet a seguir especifica um bitmap personalizado para o limite final:

Java

polyline.setEndCap(
    new CustomCap(BitmapDescriptorFactory.fromResource(R.drawable.arrow), 16));
      

Kotlin

polyline.endCap = CustomCap(BitmapDescriptorFactory.fromResource(R.drawable.arrow), 16F)
      

Ao usar um bitmap personalizado, é preciso especificar uma largura do traço de referência em pixels. A API dimensiona o bitmap de forma adequada. A largura do traço de referência é a largura do traço usada ao projetar a imagem de bitmap para o limite, na dimensão original da imagem. A largura padrão do traço de referência tem 10 pixels. Dica: para determinar a largura do traço de referência, abra sua imagem de bitmap com 100% de zoom em um editor de imagens e insira a largura desejada do traço de linha em relação à imagem.

Se você usar BitmapDescriptorFactory.fromResource() para criar o bitmap, utilize um recurso independente de densidade (nodpi).

Segmentos geodésicos

A configuração geodésica se aplica apenas a polilinhas e polígonos, e não aos círculos, porque eles não são definidos como um conjunto de segmentos.

A configuração geodésica determina como os segmentos de linha entre vértices consecutivos da polilinha/polígono são desenhados. Segmentos geodésicos são aqueles que seguem o caminho mais curto ao longo da superfície terrestre (uma esfera) e muitas vezes aparecem como linhas curvas em um mapa com a projeção Mercator. Segmentos não geodésicos são desenhados como linhas retas no mapa.

Defina essa propriedade no objeto de opção da forma chamando *Options.geodesic(), em que true indica que os segmentos serão desenhados como geodésicos, e false informa que os segmentos precisam ser desenhados como linhas retas. Se não for especificado, o padrão serão segmentos não geodésicos (false).

Após a forma ser adicionada ao mapa, a configuração geodésica poderá ser acessada chamando isGeodesic(), e ser alterada chamando setGeodesic().

Z-index

O Z-index especifica a ordem de pilha desta forma, em relação a outras sobreposições (sobreposições de solo e de bloco e outras formas) no mapa. Uma sobreposição com Z-index alto é desenhada sobre as sobreposições com Z-indexes menores. Duas sobreposições com o mesmo Z-index são desenhadas em ordem aleatória.

Os marcadores são sempre desenhados sobre as outras sobreposições, independentemente do Z-index delas.

Defina essa propriedade no objeto de opções da forma chamando *Options.zIndex(). Se não for especificado, o Z-index padrão será 0. Após a forma ser adicionada ao mapa, o Z-index poderá ser acessado chamando getZIndex(), e alterado chamando setZIndex().

Visibilidade

A visibilidade especifica se a forma precisará ser desenhada no mapa. true indica que ela será desenhada, e false, que não será. Ela permite que, temporariamente, você não exiba uma forma no mapa. Para remover permanentemente a forma do mapa, chame remove() nessa forma.

Defina essa propriedade no objeto de opções da forma chamando *Options.visible(). Se não for especificada, a visibilidade padrão será true. Após a forma ser adicionada ao mapa, a visibilidade poderá ser acessada chamando isVisible(), e alterada chamando setVisible().

Associar dados a uma forma

Você pode armazenar um objeto de dados arbitrários com uma polilinha, um polígono ou um círculo usando o método setTag() da forma e recuperar o objeto usando getTag(). Por exemplo, chame Polyline.setTag() para armazenar um objeto de dados com uma polilinha e Polyline.getTag() para recuperar o objeto de dados.

O código abaixo define uma tag arbitrária (A) para a polilinha especificada:

Java

Polyline polyline = map.addPolyline((new PolylineOptions())
    .clickable(true)
    .add(new LatLng(-35.016, 143.321),
        new LatLng(-34.747, 145.592),
        new LatLng(-34.364, 147.891),
        new LatLng(-33.501, 150.217),
        new LatLng(-32.306, 149.248),
        new LatLng(-32.491, 147.309)));

polyline.setTag("A");
      

Kotlin

val polyline = map.addPolyline(
    PolylineOptions()
        .clickable(true)
        .add(
            LatLng(-35.016, 143.321),
            LatLng(-34.747, 145.592),
            LatLng(-34.364, 147.891),
            LatLng(-33.501, 150.217),
            LatLng(-32.306, 149.248),
            LatLng(-32.491, 147.309)
        )
)
polyline.tag = "A"
      

Veja alguns exemplos de situações em que é útil armazenar e recuperar informações com formas:

  • Seu app pode oferecer vários tipos de formas, e você quer que eles se comportem de forma diferente após um clique.
  • Você está interagindo com um sistema que tem identificadores de registros exclusivos, em que as formas representam registros específicos.
  • Os dados da forma podem indicar uma prioridade para determinar o Z-index dela.