Formas

La API de Google Maps para Android ofrece distintas maneras simples de agregar formas a tus mapas a fin de personalizarlos para tu aplicación.

  • Un objeto Polyline es una serie de segmentos conectados que pueden generar cualquier forma y se pueden usar para marcar recorridos y rutas en el mapa.
  • Un objeto Polygon es una forma delimitada que se puede usar para marcar áreas en el mapa.
  • Un objeto Circle es una proyección geográficamente precisa de un círculo en la superficie terrestre dibujada en el mapa.

Puedes modificar algunas propiedades de estas formas para personalizar su aspecto.

Muestras de código

El instructivo sobre cómo agregar polígonos y polilíneas para representar áreas y rutas incluye todo el código de una app para Android simple.

Además, el repositorio ApiDemos de GitHub incluye muestras de código que ilustran el uso de las formas y sus características:

Polilíneas

La clase Polyline define un conjunto de segmentos conectados en el mapa. Un objeto Polyline consta de un conjunto de ubicaciones LatLng y crea una serie de segmentos que conectan esas ubicaciones en una secuencia ordenada.

En el siguiente video, se proporcionan ideas sobre cómo ayudar a los usuarios a llegar a donde se dirigen usando polilíneas para dibujar una ruta en el mapa.

Para crear un objeto Polyline, primero debes crear un objeto PolylineOptions y agregarle puntos. Los puntos representan un lugar de la superficie terrestre y se expresan como un objeto LatLng. Los segmentos se dibujan entre puntos según el orden en el que los agregues al objeto PolylineOptions. Para agregar puntos a un objeto PolylineOptions, llama a PolylineOptions.add(). Ten en cuenta que este método toma una cantidad variable de parámetros para que puedas agregar varios puntos a la vez (también puedes llamar a PolylineOptions.addAll(Iterable<LatLng>) si los puntos ya se encuentran en una lista).

Luego, puedes llamar a GoogleMap.addPolyline(PolylineOptions) para agregar la polilínea a un mapa. El método muestra un objeto Polyline con el que puedes modificar la polilínea posteriormente.

En el siguiente fragmento de código se muestra cómo agregar un rectángulo a un 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)
      

Si deseas modificar la forma de la polilínea una vez agregada, puedes llamar a Polyline.setPoints() y proporcionar una nueva lista de puntos para la polilínea.

Puedes personalizar el aspecto de la polilínea antes y después de agregarla al mapa. Consulta la sección Cómo personalizar los aspectos a continuación para obtener información más detallada.

Eventos de polilíneas

De forma predeterminada, no se puede hacer clic en las polilíneas. Para habilitar o inhabilitar la posibilidad de hacer clics en ellas, llama a Polyline.setClickable(boolean).

Usa un objeto OnPolylineClickListener para escuchar los eventos de clic en una polilínea en la que se puede hacer clic. Para configurar este objeto de escucha en el mapa, llama a GoogleMap.setOnPolylineClickListener(OnPolylineClickListener). Cuando un usuario haga clic en una polilínea, recibirás una devolución de llamada onPolylineClick(Polyline).

Polígonos

Los objetos Polygon son similares a los objetos Polyline, ya que constan de una serie de coordenadas en una secuencia ordenada. Sin embargo, en lugar de ser abiertos, los polígonos están diseñados para definir regiones dentro de un bucle cerrado con el interior relleno.

Puedes agregar un objeto Polygon al mapa de la misma manera en la que agregas un objeto Polyline. Primero, crea un objeto PolygonOptions y agrégale algunos puntos. Estos puntos conformarán el contorno del polígono. Luego, agrega el polígono al mapa. Para ello, llama a GoogleMap.addPolygon(PolygonOptions), que mostrará un objeto Polygon.

Con el siguiente fragmento de código, se agrega un rectángulo a un mapa (ten en cuenta que, debido a que no definimos un color de relleno y el predeterminado es transparente, el aspecto será exactamente el mismo que el de la polilínea del fragmento de código de la sección 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)
      

Si deseas modificar la forma del polígono una vez agregado, puedes llamar a Polygon.setPoints() y proporcionar una nueva lista de puntos para el contorno del polígono.

Puedes personalizar el aspecto del polígono antes y después de agregarlo al mapa. Consulta la sección Cómo personalizar los aspectos a continuación para obtener información más detallada.

Autocompletado de polígonos

El objeto Polygon del ejemplo anterior consta de cinco coordenadas, pero debes tener en cuenta que la primera y última corresponden a la misma ubicación, la cual define el bucle. Sin embargo, debido a que los polígonos definen áreas cerradas, en la práctica no necesitas definir esta última coordenada. Si la última coordenada difiere de la primera, la API "cerrará" el polígono automáticamente agregando la primera coordenada al final de la secuencia de coordenadas.

Los dos polígonos que aparecen a continuación son equivalentes y si llamas a polygon.getPoints() para cada uno se mostrarán los 4 puntos.

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

Cómo crear un polígono hueco

Se pueden combinar varias rutas en un único objeto Polygon para crear formas complejas, como aros con relleno o "donas" (donde las áreas poligonales aparecen dentro del polígono como "islas"). Las formas complejas son siempre la composición de varias rutas más simples.

Deben definirse dos rutas en la misma área. La más grande de las dos regiones define el área de relleno y es un polígono simple sin opciones adicionales. Luego, pasa una segunda ruta al método addHole(). Cuando la ruta más grande delimite a la segunda y más pequeña, parecerá que se quitó parte del polígono. Si se produce una intersección entre la porción hueca y el contorno del polígono, se renderizará este último sin relleno.

El siguiente fragmento creará un rectángulo único con una porción hueca rectangular más pequeña.

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ígonos

De forma predeterminada, no se puede hacer clic en los polígonos. Para habilitar o inhabilitar la posibilidad de hacer clics en ellos, llama a Polygon.setClickable(boolean).

Usa un objeto OnPolygonClickListener para escuchar los eventos de clic en un polígono en el que se puede hacer clic. Para configurar este objeto de escucha en el mapa, llama a GoogleMap.setOnPolygonClickListener(OnPolygonClickListener). Cuando un usuario haga clic en un polígono, recibirás una devolución de llamada onPolygonClick(Polygon).

Círculos

Además de una clase Polygon genérica, la API de Google Maps también incluye clases específicas para objetos Circle a fin de simplificar su construcción.

Para construir un círculo, debes especificar las dos propiedades siguientes:

  • center como LatLng
  • radius en metros

Por lo tanto, un círculo se define como el conjunto de todos los puntos de la superficie terrestre, que se encuentran a radius metros del objeto center especificado. Debido a la manera en que la proyección de Mercator que usa la API de Google Maps renderiza una esfera en una superficie plana, esta aparecerá casi como un círculo perfecto cuando se encuentre cerca del ecuador en el mapa y perderá cada vez más la forma circular (en la pantalla) a medida que el círculo se aleje del ecuador.

En el siguiente fragmento de código, para agregar un círculo en el mapa, se construye un objeto CircleOptions y se llama a 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 modificar la forma del círculo una vez agregado, puedes llamar a Circle.setRadius() o Circle.setCenter() y proporcionar valores nuevos.

Puedes personalizar el aspecto del círculo antes y después de agregarlo al mapa. Consulta la sección Cómo personalizar los aspectos a continuación para obtener información más detallada.

Eventos de círculos

De forma predeterminada, no se puede hacer clic en los círculos. Para habilitar o inhabilitar la posibilidad de hacer clics en ellos, llama a GoogleMap.addCircle() con CircleOptions.clickable(boolean) o llama a Circle.setClickable(boolean).

Usa un objeto OnCircleClickListener para escuchar los eventos de clic en un círculo en el que se puede hacer clic. Para configurar este objeto de escucha en el mapa, llama a GoogleMap.setOnCircleClickListener(OnCircleClickListener).

Cuando un usuario haga clic en un círculo, recibirás una devolución de llamada onCircleClick(Circle), tal como se indica en la siguiente muestra de código:

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
}
      

Cómo personalizar los aspectos

Puedes modificar el aspecto de una forma antes de agregarla al mapa (especificando la propiedad deseada en el objeto de opciones) o después de hacerlo. También se exponen métodos get para todas las propiedades a fin de que puedas acceder de manera sencilla al estado actual de la forma.

A través del siguiente fragmento de código se agrega una polilínea azul gruesa con segmentos geodésicos desde Melbourne hasta Perth. En las siguientes secciones, se explicarán estas propiedades con más detalle.

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

Nota: Si bien la mayoría de estas propiedades pueden aplicarse a cualquiera de las formas descritas, es posible que algunas de ellas no tengan sentido para ciertas formas (p. ej., un objeto Polyline no puede tener color de relleno porque no tiene área interior).

Color de trazo

El color de trazo es un elemento entero alfa/rojo/verde/azul (ARGB) de 32 bits en el que se especifican la opacidad y el color del trazo de la forma. Configura esta propiedad en el objeto de opciones de la forma. Para ello, llama a *Options.strokeColor() (o a PolylineOptions.color() en el caso de una polilínea). Si no se especifica, el color de trazo predeterminado es el negro (Color.BLACK).

Una vez que se haya agregado la forma al mapa, se podrá acceder al color de trazo llamando a getStrokeColor() (o a getColor(), si se trata de una polilínea) y se podrá cambiar llamando a setStrokeColor() (setColor() for a polyline).

Color de relleno

El color de relleno solo se aplica a los polígonos y círculos. No se aplica a las polilíneas, ya que no tienen áreas interiores definidas. En el caso de un polígono, las áreas interiores de las porciones huecas no forman parte del interior del polígono y no se les aplicará color si se configura un color de relleno.

El color de relleno es un elemento entero alfa/rojo/verde/azul (ARGB) de 32 bits en el que se especifican la opacidad y el color del interior de la forma. Llama a *Options.fillColor() para configurar esta propiedad en el objeto de opciones de la forma. Si no se especifica, el color de trazo predeterminado es transparente (Color.TRANSPARENT).

Una vez que se haya agregado la forma al mapa, se podrá acceder al color de relleno llamando a getFillColor() y se podrá cambiar llamando a setFillColor().

Ancho de trazo

Es el ancho del trazo de la línea, expresado como un número de punto flotante en píxeles (px). El ancho no se ajusta cuando se aplica zoom al mapa (p. ej., el ancho de trazo de una forma será el mismo en todos los niveles de zoom). Configura esta propiedad en el objeto de opciones de la forma. Para ello, llama a *Options.strokeWidth() (o a PolylineOptions.width(), si se trata de una polilínea). Si no se especifica, el ancho de trazo predeterminado es de 10 píxeles.

Una vez que se haya agregado la forma al mapa, se podrá acceder al color de trazo llamando a getStrokeWidth() (o a getWidth(), si se trata de una polilínea) y se podrá cambiar llamando a setStrokeWidth() (setWidth() for a polyline).

Patrón de trazo

El patrón de trazo predeterminado es una línea sólida para las polilíneas y para los contornos de polígonos y círculos. Puedes especificar un patrón de trazo personalizado de objetos PatternItem, donde cada elemento es un guion, un punto o un intervalo.

En el siguiente ejemplo, se configura el patrón de una polilínea con una secuencia repetida de puntos, seguida de un intervalo de longitud de 20 píxeles, un guion de longitud de 30 píxeles y otro intervalo de 20 píxeles.

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
      

El patrón se repite a lo largo de la línea y comienza con el primer elemento en el primer vértice especificado para la forma.

Tipos de unión

Para las polilíneas y los contornos de los polígonos, puedes especificar un tipo de unión JointType redondeada o biselada a fin de reemplazar las uniones a inglete fijas predeterminadas.

En el siguiente ejemplo se aplica un tipo de unión redondeada a una polilínea:

Java

polyline.setJointType(JointType.ROUND);
      

Kotlin

polyline.jointType = JointType.ROUND
      

El tipo de unión afecta las curvas internas de la línea. Si la línea tiene un patrón de trazo que incluye guiones, el tipo de unión también se aplica cuando un guion atraviesa una unión. Los tipos de unión no afectan los puntos, ya que siempre son circulares.

Topes de línea

Puedes especificar un estilo Cap para cada extremo de una polilínea. Las opciones son punta (predeterminado), cuadrado, redondo o un mapa de bits personalizado. Establece el estilo en PolylineOptions.startCap y PolylineOptions.endCap, o usa los métodos get y set adecuados.

En el siguiente fragmento de código, se especifica un tope redondo al comienzo de una polilínea.

Java

polyline.setStartCap(new RoundCap());
      

Kotlin

polyline.startCap = RoundCap()
      

En el siguiente fragmento, se especifica un mapa de bits personalizado para el tope final:

Java

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

Kotlin

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

Cuando usas un mapa de bits personalizado, debes especificar un ancho de trazo de referencia en píxeles. La API ajusta el mapa de bits según corresponda. El ancho del trazo de referencia es el que usaste cuando diseñaste la imagen de mapa de bits para el tope, en la dimensión original de la imagen. El ancho del trazo de referencia predeterminado es de 10 píxeles. Sugerencia: Para determinar el ancho del trazo de referencia, 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.

Si usas BitmapDescriptorFactory.fromResource() para crear el mapa de bits, asegúrate de usar un recurso independiente de la densidad (nodpi).

Segmentos geodésicos

La configuración geodésica se aplica únicamente a polilíneas y polígonos. No se aplica a los círculos porque no se definen como una colección de segmentos.

La configuración geodésica determina la manera en que se dibujan los segmentos entre vértices consecutivos de la polilínea o el polígono. Los segmentos geodésicos son aquellos que siguen la ruta más corta en la superficie terrestre (una esfera) y a menudo aparecen como líneas curvas en un mapa con una proyección de Mercator. Los segmentos no geodésicos se dibujan como líneas rectas en el mapa.

Configura esta propiedad en el objeto de opciones de la forma. Para ello, llama a *Options.geodesic(), donde true indica que los segmentos se deben dibujar como líneas geodésicas, y false indica que los segmentos se deben dibujar como líneas rectas. Si no se especifica, el valor predeterminado es el de segmentos no geodésicos (false).

Una vez que se haya agregado la forma al mapa, se podrá acceder a la configuración geodésica llamando a isGeodesic() y se podrá cambiar llamando a setGeodesic().

Índice z

El índice z especifica el orden en que se debe apilar esta forma, en relación con otras superposiciones (otras formas, superposiciones de suelo y superposiciones de mosaicos) en el mapa. Una superposición con un índice z alto se dibuja encima de las que tienen índices z más bajos. Dos superposiciones con el mismo índice z se dibujan con un orden arbitrario.

Ten en cuenta que los marcadores siempre se dibujan encima de otras superposiciones, independientemente del índice z de estas.

Llama a *Options.zIndex() para configurar esta propiedad en el objeto de opciones de la forma. Si no se especifica, el valor predeterminado del índice z es 0. Una vez que se haya agregado la forma al mapa, se podrá acceder al índice z llamando a getZIndex() y se podrá cambiar llamando a setZIndex().

Visibilidad

La visibilidad especifica si la forma debe dibujarse en el mapa: true indica que se debe dibujar y false indica que no. Te da la opción de no mostrar temporalmente una forma en el mapa. Para quitar una forma del mapa de manera permanente, llama a remove() en ella.

Llama a *Options.visible() para configurar esta propiedad en el objeto de opciones de la forma. Si no se especifica, el valor predeterminado de la visibilidad es true. Después de que se haya agregado una forma al mapa, se podrá acceder a la visibilidad llamando a isVisible() y se podrá cambiar llamando a setVisible().

Cómo asociar datos a una forma

Puedes almacenar un objeto de datos arbitrario con una polilínea, un polígono o un círculo mediante el método setTag() de la forma y recuperarlo mediante getTag(). Por ejemplo, llama a Polyline.setTag() para almacenar un objeto de datos con una polilínea y llama a Polyline.getTag() para recuperarlo.

El siguiente código define una etiqueta arbitraria (A) para la polilínea 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"
      

A continuación, se incluyen algunos ejemplos de situaciones en las que resulta útil almacenar y recuperar datos con formas:

  • Tu app proporciona distintos tipos de formas, y debes tratarlas de manera diferente cuando el usuario hace clic en ellas.
  • Interactúas con un sistema que tiene identificadores de registro únicos, y las formas representan registros específicos en ese sistema.
  • Los datos de la forma pueden indicar una prioridad para determinar el índice z de ella.