Polilíneas y polígonos para representar rutas y áreas

En este instructivo, se muestra cómo agregar un mapa de Google Maps a tu app para Android y cómo utilizar polilíneas y polígonos a fin de representar rutas y áreas en un mapa.

Sigue el instructivo a fin de compilar una app para Android con Maps SDK for Android. El entorno de desarrollo recomendado es Android Studio.

Obtén el código

En GitHub, clona o descarga el repositorio de muestras de la versión 2 de la API de Google Maps para Android.

Configura tu proyecto de desarrollo

Sigue estos pasos para crear el proyecto del instructivo en Android Studio:

  1. Descarga Android Studio y, luego, instálalo.
  2. Agrega el paquete de Servicios de Google Play a Android Studio.
  3. Clona o descarga el repositorio de muestras de la versión 2 de la API de Google Maps para Android si no lo hiciste cuando empezaste a leer este instructivo.
  4. Importa el proyecto del instructivo:

    • En Android Studio, selecciona Archivo > Nuevo > Importar proyecto.
    • Ve a la ubicación en la que guardaste el repositorio de muestras de la versión 2 de la API de Google Maps para Android tras descargarlo.
    • Busca el proyecto Polygons en esta ubicación:
      PATH-TO-SAVED-REPO/android-samples/tutorials/Polygons
    • Selecciona el directorio del proyecto y haz clic en Aceptar. Android Studio compilará tu proyecto con la herramienta de compilación Gradle.

Obtén una clave de API y habilita las API necesarias

Si deseas completar este instructivo, necesitarás una clave de API de Google autorizada a fin de utilizar Maps SDK for Android.

Haz clic en el siguiente botón para obtener una clave y activar la API.

Comenzar

Para obtener más detalles, consulta la guía completa sobre cómo obtener una clave de API.

Agrega la clave de API a tu app

  1. Edita el archivo gradle.properties de tu proyecto.
  2. Pega la clave de API en el valor de la propiedad GOOGLE_MAPS_API_KEY. Cuando compiles tu app, Gradle copiará la clave de API en el manifiesto de Android de la app, como se explica a continuación.

    GOOGLE_MAPS_API_KEY=PASTE-YOUR-API-KEY-HERE
    

Compila y ejecuta tu app

  1. Conecta un dispositivo Android a tu computadora. Sigue las instrucciones a fin de habilitar las opciones para desarrolladores en tu dispositivo Android y configurar el sistema para que lo detecte. También puedes utilizar el Administrador de dispositivos virtuales de Android (AVD) para configurar esos dispositivos. Al elegir un emulador, asegúrate de seleccionar una imagen que incluya las API de Google. Para obtener más detalles, consulta la guía de introducción.
  2. En Android Studio, haz clic en la opción Ejecutar del menú (o en el ícono del botón de reproducción). Selecciona un dispositivo según se solicite.

Android Studio invoca a Gradle para compilar la app y, luego, la ejecuta en el dispositivo o el emulador.

Deberías ver un mapa con dos polígonos superpuestos sobre Australia, similar al de la imagen que se incluye esta página.

Solución de problemas:

Comprende el código

En esta sección del instructivo, se explican los componentes más importantes de la app Polygons para ayudarte a comprender cómo compilar una app similar.

Verifica el manifiesto de Android

Observa los siguientes elementos en el archivo AndroidManifest.xml de tu app:

  • Agrega un elemento meta-data para incorporar la versión de Servicios de Google Play con la que se compiló la app.

    <meta-data
        android:name="com.google.android.gms.version"
        android:value="@integer/google_play_services_version" />
    
  • Agrega un elemento meta-data en el que se especifique tu clave de API. En el ejemplo incluido en este instructivo, se mapea el valor de la clave de API a una string google_maps_key. Cuando compiles tu app, Gradle copiará la clave de API del archivo gradle.properties de tu proyecto en el valor de la string.

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

    Para ver cómo se mapea la clave de API al valor de la string, consulta el archivo build.gradle de tu app. Este incluye la siguiente línea que mapea la string google_maps_key a la propiedad GOOGLE_MAPS_API_KEY de Gradle:

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

A continuación, se muestra un ejemplo completo de un manifiesto:

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

Agrega un mapa

Muestra un mapa con Maps SDK for Android.

  1. Agrega un elemento <fragment> al archivo de diseño de tu actividad, activity_maps.xml. Este elemento define un fragmento (SupportMapFragment) para que actúe como contenedor del mapa y proporcione acceso al objeto GoogleMap. En el instructivo, se utiliza la versión de la biblioteca de compatibilidad de Android correspondiente al fragmento de mapa para garantizar la retrocompatibilidad con versiones anteriores del marco de trabajo de 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. En el método onCreate() de tu actividad, establece el archivo de diseño como la vista de contenido. Llama a FragmentManager.findFragmentById() a fin de generar un controlador para el fragmento de mapa. Luego, utiliza getMapAsync() a fin de registrarte para la devolución de llamada del mapa:

    @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. Implementa la interfaz OnMapReadyCallback y anula el método onMapReady(). La API invoca esta devolución de llamada cuando el objeto GoogleMap está disponible, por lo que puedes agregar objetos al mapa y personalizarlo aún más para tu app:

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

Agrega una polilínea para dibujar una línea en el mapa

Una polilínea (Polyline) es una serie de segmentos de líneas conectadas. Las polilíneas resultan útiles para representar rutas, trayectos o demás conexiones entre diferentes ubicaciones en el mapa.

  1. Crea un objeto PolylineOptions y agrégale puntos. Cada punto representa una ubicación en el mapa, la cual defines con un objeto LatLng que contiene los valores de latitud y longitud. La muestra de código que se incluye a continuación crea una polilínea de 6 puntos.

  2. Llama a GoogleMap.addPolyline() para agregar la polilínea al 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)));
    

Establece la opción clickable de la polilínea en true si deseas controlar los eventos de clic en la polilínea. Encontrarás información adicional sobre cómo controlar los eventos más adelante en este instructivo.

Almacena datos arbitrarios con una polilínea

Puedes almacenar objetos de datos arbitrarios con las polilíneas y otros objetos geométricos.

  1. Llama a Polyline.setTag() para almacenar un objeto de datos con la polilínea. El siguiente código define una etiqueta arbitraria (A) que indica un tipo de polilínea:

    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. Recupera los datos con Polyline.getTag(), como se muestra en la siguiente sección.

Personaliza el diseño de la polilínea

Puedes especificar varias propiedades de diseño en el objeto PolylineOptions. Las opciones de diseño incluyen el color, el ancho y el patrón de trazo, los tipos de unión y los topes de inicio y finalización. Si no especificas una propiedad en particular, la API utilizará un valor predeterminado para ella.

El siguiente código aplica un tope redondo al final de la línea y otro diferente al inicio, según el tipo de polilínea, donde el tipo es una propiedad arbitraria almacenada en el objeto de datos de la polilínea. La muestra también especifica el ancho y el color de trazo, así como un tipo de unión:

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

En el código anterior, se especifica un mapa de bits personalizado para el tope de inicio de la polilínea tipo A y se define un ancho de trazo de referencia de 10 píxeles. La API escala el mapa de bits en función del ancho de trazo de referencia. Cuando definas el ancho de trazo de referencia, proporciona el ancho que utilizaste cuando diseñaste la imagen de mapa de bits, en su dimensión original. Sugerencia: Abre tu imagen de mapa de bits con un zoom del 100% en un editor de imágenes y define el ancho deseado para el trazo de la línea en relación con la imagen.

Obtén más información sobre los topes de línea y otras opciones para personalizar las formas.

Controla los eventos de clic en la polilínea

  1. Llama a Polyline.setClickable() para habilitar la posibilidad de hacer clics en la polilínea. De forma predeterminada, no se puede hacer clic en las polilíneas, y tu app no recibirá una notificación cuando el usuario las presione.

  2. Implementa la interfaz OnPolylineClickListener y llama a GoogleMap.setOnPolylineClickListener() para configurar el objeto de escucha en el 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. Anula el método de devolución de llamada onPolylineClick(). En el siguiente ejemplo, cada vez que el usuario hace clic en la polilínea, se alterna entre dos patrones de trazo, específicamente, una "línea continua" y una "línea de puntos":

    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();
    }
    

Agrega polígonos para representar áreas en el mapa

Un polígono (Polygon) es una forma que consiste en una serie de coordenadas en una secuencia ordenada, similar a una polilínea (Polyline). La diferencia radica en que el polígono define un área cerrada con un interior que se puede rellenar, mientras que una polilínea tiene extremos abiertos.

  1. Crea un objeto PolygonOptions y agrégale puntos. Cada punto representa una ubicación en el mapa, la cual defines con un objeto LatLng que contiene los valores de latitud y longitud. La siguiente muestra de código crea un polígono de 4 puntos.

  2. Llama a Polygon.setClickable() para habilitar la posibilidad de hacer clic en el polígono. De forma predeterminada, no se puede hacer clic en los polígonos, y tu app no recibirá una notificación cuando el usuario los presione. Para controlar los eventos de clic en los polígonos, se debe seguir un proceso similar al que permite controlar los eventos relacionados con las polilíneas, el cual se describe más arriba en este instructivo.

  3. Llama a GoogleMap.addPolygon() para agregar el polígono al mapa.

  4. Llame a Polygon.setTag() para almacenar un objeto de datos con el polígono. El siguiente código define un tipo arbitrario (alpha) para el 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");
    

Personaliza el diseño del polígono

Puedes especificar una serie de propiedades de diseño en el objeto PolygonOptions. Las opciones de diseño incluyen el color, el ancho y el patrón de trazo, los tipos de unión y el color de relleno. Si no especificas una propiedad en particular, la API utilizará un valor predeterminado para ella.

El siguiente código aplica colores y patrones de trazo específicos según el tipo de polígono, donde el tipo es una propiedad arbitraria almacenada en el objeto de datos del 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);
}

Obtén más información sobre los patrones de trazo y otras opciones para personalizar las formas.

Próximos pasos

Obtén más información sobre el objeto Circle. Este tipo de objeto es similar al polígono, pero tiene propiedades que reflejan la forma de un círculo.