Polilinhas e polígonos para representar trajetos e áreas

Neste tutorial, mostramos como adicionar um mapa do Google ao seu app para Android e usar polilinhas e polígonos para representar trajetos e áreas.

Siga o tutorial e crie um app para Android usando o Maps SDK for Android. O ambiente recomendado para desenvolvedores é o Android Studio.

Acessar o código

Clone ou faça o download do repositório de exemplos da API Google Maps Android v2 do GitHub.

Configurar seu projeto de desenvolvimento

Siga estas etapas para criar o projeto de tutorial no Android Studio.

  1. Faça o download do Android Studio e instale-o.
  2. Adicione o pacote Google Play Services ao Android Studio.
  3. Clone ou faça o download do repositório de exemplos da API Google Maps Android v2 se não tiver feito isso no início deste tutorial.
  4. Importe o projeto de tutorial:

    • No Android Studio, selecione File > New > Import Project.
    • Acesse o local onde você salvou o repositório de exemplos da API Google Maps Android v2 após fazer o download.
    • Encontre o projeto Polygons neste local:
      PATH-TO-SAVED-REPO/android-samples/tutorials/Polygons
    • Selecione o diretório do projeto e clique em OK. O Android Studio criará seu projeto usando a ferramenta Gradle.

Receber uma chave de API e ativar as APIs necessárias

Para concluir este tutorial, você precisa de uma chave de API do Google que possa usar o Maps SDK for Android.

Clique no botão abaixo para acessar uma chave e ativar a API.

Primeiros passos

Se quiser mais detalhes, consulte o guia completo para acessar uma chave de API.

Adicionar a chave de API ao app

  1. Edite o arquivo gradle.properties do seu projeto.
  2. Cole sua chave de API no valor da propriedade GOOGLE_MAPS_API_KEY. Quando você cria o app, o Gradle copia essa chave no manifesto do Android, conforme explicado abaixo.

    GOOGLE_MAPS_API_KEY=PASTE-YOUR-API-KEY-HERE
    

Criar e executar seu app

  1. Conecte um dispositivo Android ao computador. Siga as instruções se quiser ativar as opções para desenvolvedores no seu dispositivo Android e configurar o sistema de modo a detectar o aparelho. Também é possível usar o gerenciador de Dispositivo virtual Android (AVD, na sigla em inglês) para instalar um dispositivo virtual. Ao escolher um emulador, selecione uma imagem que inclua as APIs do Google. Para mais detalhes, consulte o guia de primeiros passos.
  2. No Android Studio, clique na opção de menu Run ou no ícone do botão de reprodução. Escolha um dispositivo quando solicitado.

O Android Studio invoca o Gradle para criar o app e, em seguida, executa o aplicativo no aparelho ou no emulador.

Você verá um mapa com dois polígonos sobrepostos na Austrália, como na imagem desta página.

Solução de problemas:

Entender o código

Nesta parte do tutorial, explicamos as partes mais importantes do app Polygons para mostrar como criar um aplicativo semelhante.

Verificar o manifesto do Android

Observe os seguintes elementos no arquivo AndroidManifest.xml do seu app:

  • Adicione um elemento meta-data para incorporar a versão do Google Play Services com que o app foi compilado.

    <meta-data
        android:name="com.google.android.gms.version"
        android:value="@integer/google_play_services_version" />
    
  • Inclua um elemento meta-data que especifique sua chave de API. O exemplo que acompanha este tutorial mapeia o valor da chave de API para uma string google_maps_key. Quando você cria o app, o Gradle copia essa chave do arquivo gradle.properties do seu projeto para o valor da string.

    <meta-data
      android:name="com.google.android.geo.API_KEY"
      android:value="@string/google_maps_key" />
    

    Se você quiser analisar o mapeamento, observe o build.gradle do app. Ele contém a seguinte linha que mapeia a string google_maps_key para a propriedade GOOGLE_MAPS_API_KEY do Gradle:

    resValue "string", "google_maps_key",
            (project.findProperty("GOOGLE_MAPS_API_KEY") ?: "")
    

Confira o exemplo completo de um manifesto:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.polygons">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />

        <!--
             The API key for Google Maps-based APIs.
        -->
        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="@string/google_maps_key" />

        <activity
            android:name="com.example.polygons.PolyActivity"
            android:label="@string/title_activity_maps">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

Adicionar um mapa

Exiba um mapa usando o Maps SDK for Android.

  1. Adicione um elemento <fragment> ao arquivo de layout da sua atividade, activity_maps.xml. Esse elemento define um SupportMapFragment para atuar como um contêiner do mapa e conceder acesso ao objeto GoogleMap. O tutorial usa a versão do fragmento de mapa da Biblioteca de Suporte do Android para oferecer compatibilidade com versões anteriores do framework Android.

    <fragment xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/map"
        android:name="com.google.android.gms.maps.SupportMapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.example.polygons.PolyActivity" />
    
    
  2. No método onCreate() da sua atividade, defina o arquivo de layout como a visualização de conteúdo. Gere um identificador para o fragmento de mapa chamando FragmentManager.findFragmentById(). Em seguida, use getMapAsync() para se registrar no callback:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        // Retrieve the content view that renders the map.
        setContentView(R.layout.activity_maps);
    
        // Get the SupportMapFragment and request notification when the map is ready to be used.
        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(map);
        mapFragment.getMapAsync(this);
    }
    
  3. Implemente a interface OnMapReadyCallback e modifique o método onMapReady(). A API invoca esse callback quando o objeto GoogleMap está disponível. Assim, você pode adicionar objetos ao mapa e personalizá-lo ainda mais:

    public class PolyActivity extends AppCompatActivity
            implements
                    OnMapReadyCallback,
                    GoogleMap.OnPolylineClickListener,
                    GoogleMap.OnPolygonClickListener {
    
        // More code goes here, including the onCreate() method described above.
    
        @Override
        public void onMapReady(GoogleMap googleMap) {
    
            // Add polylines and polygons to the map. This section shows just
            // a single polyline. Read the rest of the tutorial to learn more.
            Polyline polyline1 = googleMap.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)));
    
            // Position the map's camera near Alice Springs in the center of Australia,
            // and set the zoom factor so most of Australia shows on the screen.
            googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(-23.684, 133.903), 4));
    
            // Set listeners for click events.
            googleMap.setOnPolylineClickListener(this);
            googleMap.setOnPolygonClickListener(this);
        }
    }
    

Adicionar uma polilinha para desenhar uma linha no mapa

Uma Polyline é uma série de segmentos de linha conectados. As polilinhas são úteis para representar trajetos, caminhos ou outras conexões entre locais no mapa.

  1. Crie um objeto PolylineOptions e adicione pontos a ele. Cada ponto representa um local no mapa, que você define com um objeto LatLng contendo valores de latitude e longitude. A amostra de código abaixo cria uma polilinha com seis pontos.

  2. Chame GoogleMap.addPolyline() para adicionar a polilinha ao mapa.

    Polyline polyline1 = googleMap.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)));
    

Defina a opção clickable da polilinha como true se você quiser gerenciar os eventos de clique dela. Falaremos mais sobre gerenciamento de eventos mais adiante neste tutorial.

Armazenar dados arbitrários com uma polilinha

Você pode armazenar objetos de dados arbitrários com polilinhas e outros objetos de geometria.

  1. Chame Polyline.setTag() para armazenar um objeto de dados com a polilinha. O código abaixo define uma tag arbitrária (A) indicando um tipo de polilinha.

    Polyline polyline1 = googleMap.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)));
    // Store a data object with the polyline, used here to indicate an arbitrary type.
    polyline1.setTag("A");
    
  2. Recupere os dados usando Polyline.getTag(), conforme a seção a seguir.

Adicionar um estilo personalizado à polilinha

Você pode especificar várias propriedades de estilo no objeto PolylineOptions. As opções de estilo incluem a cor, a largura e o padrão do traço, os tipos de junção e os limites inicial e final. Se você não definir uma propriedade específica, a API usará um padrão.

No código a seguir, um limite redondo é aplicado ao fim da linha, além de um limite inicial diferente, dependendo do tipo da polilinha. Esse tipo é uma propriedade arbitrária armazenada no objeto de dados da polilinha. A amostra também especifica a largura e a cor do traço, bem como o tipo de junção:

private static final int COLOR_BLACK_ARGB = 0xff000000;
private static final int POLYLINE_STROKE_WIDTH_PX = 12;

private void stylePolyline(Polyline polyline) {
    String type = "";
    // Get the data object stored with the polyline.
    if (polyline.getTag() != null) {
        type = polyline.getTag().toString();
    }

    switch (type) {
        // If no type is given, allow the API to use the default.
        case "A":
            // Use a custom bitmap as the cap at the start of the line.
            polyline.setStartCap(
                    new CustomCap(
                            BitmapDescriptorFactory.fromResource(R.drawable.ic_arrow), 10));
            break;
        case "B":
            // Use a round cap at the start of the line.
            polyline.setStartCap(new RoundCap());
            break;
    }

    polyline.setEndCap(new RoundCap());
    polyline.setWidth(POLYLINE_STROKE_WIDTH_PX);
    polyline.setColor(COLOR_BLACK_ARGB);
    polyline.setJointType(JointType.ROUND);
}

O código acima especifica um bitmap personalizado para o limite inicial da polilinha do tipo A e define uma largura de traço de referência de 10 pixels. A API dimensiona o bitmap com base na largura atual. Ao especificar a largura, informe o valor usado ao criar a imagem em bitmap, com a dimensão original da imagem. Dica: abra a imagem em bitmap com zoom de 100% em um editor e insira a largura desejada do traço de linha em relação à imagem.

Leia mais sobre limites de linha e outras opções para personalizar formas.

Processar eventos de clique na polilinha

  1. Para tornar a polilinha clicável, chame Polyline.setClickable(). Por padrão, as polilinhas não são clicáveis, e seu app não recebe uma notificação quando o usuário toca nelas.

  2. Implemente a interface OnPolylineClickListener e chame GoogleMap.setOnPolylineClickListener() para definir o listener no mapa:

    public class PolyActivity extends AppCompatActivity
            implements
                    OnMapReadyCallback,
                    GoogleMap.OnPolylineClickListener,
                    GoogleMap.OnPolygonClickListener {
    
        @Override
        public void onMapReady(GoogleMap googleMap) {
            // Add a polyline to the map.
            Polyline polyline1 = googleMap.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)));
    
            // Set listeners for click events.
            googleMap.setOnPolylineClickListener(this);
            googleMap.setOnPolygonClickListener(this);
        }
    }
    
  3. Modifique o método de callback onPolylineClick(). No exemplo a seguir, alternamos o padrão de traço da linha entre sólido e pontilhado a cada vez que o usuário clica na polilinha:

    private static final PatternItem DOT = new Dot();
    private static final PatternItem GAP = new Gap(PATTERN_GAP_LENGTH_PX);
    //
    // Create a stroke pattern of a gap followed by a dot.
    private static final List<PatternItem> PATTERN_POLYLINE_DOTTED = Arrays.asList(GAP, DOT);
    
    @Override
    public void onPolylineClick(Polyline polyline) {
        // Flip from solid stroke to dotted stroke pattern.
        if ((polyline.getPattern() == null) || (!polyline.getPattern().contains(DOT))) {
            polyline.setPattern(PATTERN_POLYLINE_DOTTED);
        } else {
            // The default pattern is a solid stroke.
            polyline.setPattern(null);
        }
    
        Toast.makeText(this, "Route type " + polyline.getTag().toString(),
                Toast.LENGTH_SHORT).show();
    }
    

Adicionar polígonos para representar áreas no mapa

Um Polygon é uma forma que consiste em várias coordenadas em uma sequência ordenada, semelhante a uma Polyline. A diferença é que o polígono define uma área fechada com um interior preenchível, enquanto uma polilinha é aberta.

  1. Crie um objeto PolygonOptions e adicione pontos a ele. Cada ponto representa um local no mapa, que você define com um objeto LatLng contendo valores de latitude e longitude. A amostra de código abaixo cria um polígono com quatro pontos.

  2. Para tornar o polígono clicável, chame Polygon.setClickable(). Por padrão, os polígonos não são clicáveis, e seu app não recebe uma notificação quando o usuário toca neles. A forma de lidar com eventos de clique no polígono é igual ao gerenciamento de eventos em polilinhas, que já foi explicado neste tutorial.

  3. Chame GoogleMap.addPolygon() para adicionar o polígono ao mapa.

  4. Chame Polygon.setTag() para armazenar um objeto de dados com o polígono. O código abaixo define um tipo arbitrário (alpha) para o polígono.

    Polygon polygon1 = googleMap.addPolygon(new PolygonOptions()
            .clickable(true)
            .add(
                    new LatLng(-27.457, 153.040),
                    new LatLng(-33.852, 151.211),
                    new LatLng(-37.813, 144.962),
                    new LatLng(-34.928, 138.599)));
    // Store a data object with the polygon, used here to indicate an arbitrary type.
    polygon1.setTag("alpha");
    

Adicionar um estilo personalizado ao polígono

É possível especificar várias propriedades de estilo no objeto PolygonOptions. As opções de estilo incluem a cor, a largura, o padrão e os tipos de junção do traço, além da cor de preenchimento. Se você não definir uma propriedade específica, a API usará um padrão.

No código a seguir, cores específicas e padrões de traço são aplicados, dependendo do tipo do polígono. Esse tipo é uma propriedade arbitrária armazenada no objeto de dados do polígono:

private static final int COLOR_BLACK_ARGB = 0xff000000;
private static final int COLOR_WHITE_ARGB = 0xffffffff;
private static final int COLOR_GREEN_ARGB = 0xff388E3C;
private static final int COLOR_PURPLE_ARGB = 0xff81C784;
private static final int COLOR_ORANGE_ARGB = 0xffF57F17;
private static final int COLOR_BLUE_ARGB = 0xffF9A825;

private static final int POLYGON_STROKE_WIDTH_PX = 8;
private static final int PATTERN_DASH_LENGTH_PX = 20;
private static final int PATTERN_GAP_LENGTH_PX = 20;
private static final PatternItem DOT = new Dot();
private static final PatternItem DASH = new Dash(PATTERN_DASH_LENGTH_PX);
private static final PatternItem GAP = new Gap(PATTERN_GAP_LENGTH_PX);

// Create a stroke pattern of a gap followed by a dash.
private static final List<PatternItem> PATTERN_POLYGON_ALPHA = Arrays.asList(GAP, DASH);

// Create a stroke pattern of a dot followed by a gap, a dash, and another gap.
private static final List<PatternItem> PATTERN_POLYGON_BETA =
        Arrays.asList(DOT, GAP, DASH, GAP);

private void stylePolygon(Polygon polygon) {
    String type = "";
    // Get the data object stored with the polygon.
    if (polygon.getTag() != null) {
        type = polygon.getTag().toString();
    }

    List<PatternItem> pattern = null;
    int strokeColor = COLOR_BLACK_ARGB;
    int fillColor = COLOR_WHITE_ARGB;

    switch (type) {
        // If no type is given, allow the API to use the default.
        case "alpha":
            // Apply a stroke pattern to render a dashed line, and define colors.
            pattern = PATTERN_POLYGON_ALPHA;
            strokeColor = COLOR_GREEN_ARGB;
            fillColor = COLOR_PURPLE_ARGB;
            break;
        case "beta":
            // Apply a stroke pattern to render a line of dots and dashes, and define colors.
            pattern = PATTERN_POLYGON_BETA;
            strokeColor = COLOR_ORANGE_ARGB;
            fillColor = COLOR_BLUE_ARGB;
            break;
    }

    polygon.setStrokePattern(pattern);
    polygon.setStrokeWidth(POLYGON_STROKE_WIDTH_PX);
    polygon.setStrokeColor(strokeColor);
    polygon.setFillColor(fillColor);
}

Leia mais sobre padrões de traço e outras opções para personalizar formas.

Próximas etapas

Saiba mais sobre o objeto Circle. Os círculos são semelhantes aos polígonos, mas têm propriedades que refletem a forma de um círculo.