Cámara y vista

Los mapas del SDK de Maps para Android se pueden inclinar y rotar con gestos sencillos. Esto permite a los usuarios ajustar el mapa con una orientación que tenga sentido para ellos. Con cualquier nivel de zoom, puedes desplazar el mapa lateralmente o cambiar su perspectiva con una latencia muy reducida gracias a la menor superficie de los mosaicos de mapas basados en vectores.

Muestras de código

El repositorio ApiDemos de GitHub incluye una muestra de código que ilustra las características de las cámaras:

Introducción

Al igual que Google Maps en la Web, el SDK de Maps para Android representa la superficie de la Tierra (una esfera) en la pantalla de tu dispositivo (un plano) a través de la proyección de Mercator. Al este y al oeste, el mapa se repite infinitamente a medida que el mundo se pliega sobre sí mismo a la perfección. Al norte y al sur, el mapa tiene una limitación aproximada de 85 grados en ambas direcciones.

Nota: La proyección de Mercator tiene un ancho limitado en sentido longitudinal, pero un alto ilimitado en sentido latitudinal. Las imágenes del mapa base se "recortan" mediante la proyección de Mercator a aproximadamente +/- 85° para que la forma del mapa resultante sea cuadrada, lo cual hace más sencilla la lógica de selección de mosaicos.

El SDK de Maps para Android te permite cambiar el punto de vista del usuario modificando la cámara del mapa.

Los cambios en la cámara no producirán cambios en los marcadores, las superposiciones ni ningún otro gráfico que agregues, aunque probablemente te convenga modificar los elementos que agregues para que se ajusten mejor a la vista nueva.

Debido a que es posible escuchar los gestos de los usuarios en el mapa, puedes cambiar el mapa en respuesta a las solicitudes de los usuarios. Por ejemplo, el método de devolución de llamada OnMapClickListener.onMapClick() responde a una sola presión en el mapa. Debido a que el método recibe la latitud y longitud de la ubicación en la que se realiza la presión, puedes responder desplazándote lateralmente o haciendo zoom en dicho punto. Se encuentran disponibles métodos similares para responder a presiones en el cuadro de un marcador o a un gesto de arrastre en un marcador.

También puedes escuchar movimientos de la cámara, de manera que tu app reciba una notificación cuando la cámara comience a moverse, esté en movimiento o se detenga. Para obtener información detallada, consulta la guía sobre los eventos de cambio de cámara.

Edificios 3D en el mapa

A través de una vista ampliada, en muchas ciudades habrá edificios 3D visibles, tal como se ve en la siguiente imagen de Vancouver, Canadá. Para inhabilitar los edificios 3D, llama a GoogleMap.setBuildingsEnabled(false).

Mapa de Vancouver, Canadá

La posición de la cámara

La vista de mapa responde a un modelo en el cual una cámara apunta hacia abajo sobre un plano. La posición de la cámara (y, por lo tanto, la renderización del mapa) se especifica a través de las siguientes propiedades: objetivo (ubicación de latitud/longitud), rumbo, inclinación y zoom.

Diagrama de propiedades de la cámara

Objetivo (ubicación)

El objetivo de la cámara es la ubicación del centro del mapa, especificada como coordenadas de latitud y longitud.

Rumbo (orientación)

El rumbo de la cámara es la dirección hacia la que apunta una línea vertical en el mapa, medida en grados en sentido horario partiendo desde el norte. Quienes conducen un auto a menudo giran los mapas de rutas para alinearlos con la dirección en la que se desplazan, mientras que los senderistas que usan mapas y brújula suelen orientar los mapas de modo que la línea vertical apunte hacia el norte. La API de Google Maps te permite cambiar la alineación o el rumbo de un mapa. Por ejemplo, un rumbo de 90 grados da como resultado un mapa cuya orientación hacia arriba apunta al este.

Inclinación (ángulo de visión)

La inclinación es la posición de la cámara en un arco entre el punto que se encuentra directamente sobre la posición central del mapa y la superficie de la Tierra, medida en grados a partir del nadir (la dirección que apunta justo debajo de la cámara). Cuando cambias el ángulo de visión, el mapa aparece en perspectiva; los elementos apartados se ven más pequeños y los cercanos, más grandes. En las siguientes ilustraciones se demuestra esto.

En las siguientes imágenes, el ángulo de visión es de 0 grados. En la primera imagen, se muestra un esquema de esto. La posición 1 es la posición de la cámara, y la 2 es la del mapa actual. El mapa resultante se muestra debajo.

Captura de pantalla de un mapa con una cámara ubicada a un ángulo de visión de 0 grados, con un nivel de zoom de 18
El mapa con el ángulo de visión predeterminado de la cámara
Diagrama en el que se muestra la posición predeterminada de la cámara, directamente sobre la posición del mapa, en un ángulo de 0 grados
El ángulo de visión predeterminado de la cámara

En las siguientes imágenes, el ángulo de visión es de 45 grados. Ten en cuenta que la cámara no se encuentra inclinada a 45 grados. En cambio, se desplaza a la mitad del trayecto de un arco entre el cénit (0 grados) y el suelo (90 grados), hasta la posición 3. La cámara continúa apuntando hacia el punto central del mapa, pero ahora puede verse el área representada por la línea en la posición 4.

Captura de pantalla de un mapa con una cámara ubicada a un ángulo de visión de 45 grados, con un nivel de zoom de 18
El mapa se muestra con un ángulo de visión de 45 grados
Diagrama en el que se muestra el ángulo de visión de la cámara establecido en 45 grados, con el nivel de zoom aún establecido en 18
Un ángulo de visión de la cámara de 45 grados

El mapa de esta captura de pantalla continúa centrado en el mismo punto que el mapa original, aunque aparecieron más elementos en la parte superior. A medida que el ángulo supera los 45 grados, los elementos que se encuentran entre la posición del mapa y la cámara tienen un tamaño proporcionalmente mayor, mientras que los elementos que se encuentran más allá de la posición del mapa tienen un tamaño proporcionalmente menor. Esto genera un efecto tridimensional.

Zoom

El nivel de zoom de la cámara determina la escala del mapa. A mayores niveles de zoom pueden observarse más detalles en la pantalla, mientras que a menores niveles de zoom el mundo se ve de manera más abarcadora. En el nivel de zoom 0, la escala del mapa hace que el mundo tenga un ancho aproximado de 256 dp (píxeles independientes de la densidad).

Un aumento de 1 punto en el nivel de zoom duplica el ancho del mundo en la pantalla. Por lo tanto, con el nivel de zoom N, el ancho del mundo equivale aproximadamente a 256 * 2N dp; es decir, en el nivel de zoom 2, el ancho del mundo en su totalidad es de aproximadamente 1,024 dp. Ten en cuenta que el nivel de zoom no necesariamente debe ser un valor entero. La variedad de niveles de zoom que permite el mapa depende de varios factores, como la ubicación, el tipo de mapa y el tamaño de la pantalla. Cualquier número que esté fuera del rango se convertirá en el siguiente valor válido más cercano, que puede ser el nivel de zoom mínimo o el nivel de zoom máximo. En la siguiente lista, se muestra el nivel aproximado de detalle que puedes esperar ver en cada nivel de zoom:

  • 1: Mundo
  • 5: Tierra firme y continente
  • 10: Ciudad
  • 15: Calles
  • 20: Edificios

En las siguientes imágenes, se muestra el aspecto visual de los diferentes niveles de zoom:

Captura de pantalla de un mapa con un nivel de zoom 5
Mapa con un nivel de zoom 5
Captura de pantalla de un mapa con un nivel de zoom 15
Mapa con un nivel de zoom 15
Captura de pantalla de un mapa con un nivel de zoom 20
Mapa con un nivel de zoom 20

Nota: Debido al tamaño y la densidad de la pantalla, es posible que algunos dispositivos no admitan los niveles de zoom más bajos. Usa GoogleMap.getMinimumZoomLevel() para obtener el nivel de zoom mínimo posible para el mapa. Si necesitas mostrar todo el mundo en el viewport, te recomendamos usar el modo lite.

Cómo mover la cámara

La API de Google Maps te permite cambiar qué parte del mundo está visible en el mapa. Para hacerlo, cambia la posición de la cámara (en lugar de mover el mapa).

Cuando haces cambios en la cámara, tienes la opción de animar el movimiento resultante. En la animación se interpolan los atributos existentes y nuevos de la cámara. También puedes controlar la duración de la animación.

Para cambiar la posición de la cámara, debes especificar el cambio que deseas hacer. Para ello, usa CameraUpdate. La API de Google Maps te permite crear muchos tipos diferentes de CameraUpdate mediante CameraUpdateFactory. Están disponibles las siguientes opciones:

Cómo cambiar el nivel de zoom y establecer el zoom mínimo y máximo

CameraUpdateFactory.zoomIn() y CameraUpdateFactory.zoomOut() te proporcionan un objeto CameraUpdate que cambia el nivel de zoom en un valor de 1.0 y, al mismo tiempo, mantiene todas las demás propiedades como están.

CameraUpdateFactory.zoomTo(float) te proporciona un objeto CameraUpdate que cambia el nivel de zoom al valor indicado y, al mismo tiempo, mantiene todas las demás propiedades como están.

CameraUpdateFactory.zoomBy(float) y CameraUpdateFactory.zoomBy(float, Point) te proporcionan un objeto CameraUpdate que aumenta (o disminuye, si el valor es negativo) el nivel de zoom según el valor indicado. El último corrige el punto dado en la pantalla para que permanezca en la misma ubicación (latitud/longitud) y, por eso, es posible que cambie la ubicación de la cámara para lograrlo.

Puede resultarte útil configurar tus niveles de zoom mínimo y máximo preferidos. Esto resulta útil, por ejemplo, para controlar la experiencia del usuario si en tu app se muestra un área definida alrededor de un lugar de interés o si usas una superposición de mosaicos personalizada con un conjunto limitado de niveles de zoom.

Java

private GoogleMap map;
    map.setMinZoomPreference(6.0f);
    map.setMaxZoomPreference(14.0f);
      

Kotlin

private lateinit var map: GoogleMap

    map.setMinZoomPreference(6.0f)
    map.setMaxZoomPreference(14.0f)
      

Ten en cuenta que, en virtud de ciertas consideraciones técnicas, podría impedirse que la API permita a los usuarios acercar o alejar demasiado el mapa. Por ejemplo, un mapa satelital o terrestre puede tener un nivel de zoom máximo inferior al de los mosaicos del mapa base.

Cómo cambiar la posición de la cámara

Existen dos métodos de conveniencia para los cambios de posición comunes. CameraUpdateFactory.newLatLng(LatLng) te proporciona un objeto CameraUpdate que cambia la latitud y longitud de la cámara y, al mismo tiempo, mantiene todas las demás propiedades. CameraUpdateFactory.newLatLngZoom(LatLng, float) te proporciona un objeto CameraUpdate que cambia la latitud, la longitud y el zoom de la cámara y, al mismo tiempo, mantiene todas las demás propiedades.

Para obtener una flexibilidad total al cambiar la posición de la cámara, usa CameraUpdateFactory.newCameraPosition(CameraPosition), que proporciona un objeto CameraUpdate que mueve la cámara a la posición indicada. Es posible obtener un objeto CameraPosition de forma directa mediante new CameraPosition(), o bien mediante un CameraPosition.Builder a través de new CameraPosition.Builder().

Desplazamiento lateral (vertical)

CameraUpdateFactory.scrollBy(float, float) te proporciona un objeto CameraUpdate que cambia la latitud y longitud de la cámara para que el mapa se mueva según la cantidad de píxeles especificada. Un valor de "x" positivo hace que la cámara se desplace hacia la derecha, de modo que el mapa parezca desplazarse hacia la izquierda. Un valor de "y" positivo hace que la cámara se desplace hacia abajo, de modo que el mapa parezca desplazarse hacia arriba. Por el contrario, un valor de "x" negativo hace que la cámara se desplace hacia la izquierda, de modo que el mapa parezca desplazarse hacia la derecha, y un valor de "y" negativo hace que la cámara se desplace hacia arriba. El desplazamiento vertical se relaciona con la orientación actual de la cámara. Por ejemplo, si la cámara tiene un rumbo de 90 grados, el este equivale a "arriba".

Cómo configurar límites

Cómo configurar los límites del mapa

A veces, resulta útil mover la cámara de modo que sea visible un área de interés completa con el mayor nivel de zoom posible. Por ejemplo, si muestras la totalidad de las gasolineras a ocho kilómetros alrededor de la posición actual del usuario, te recomendamos que muevas la cámara de modo que puedan verse todas en la pantalla. Para ello, primero calcula el objeto LatLngBounds que deseas que se vea en la pantalla. Luego, puedes usar CameraUpdateFactory.newLatLngBounds(LatLngBounds bounds, int padding) para obtener un objeto CameraUpdate que cambia la posición de la cámara de modo que el objeto LatLngBounds dado se ajuste completamente al mapa, teniendo en cuenta el padding (en píxeles) especificado. El objeto CameraUpdate que se muestra garantiza que el espacio (en píxeles) entre los límites indicados y el borde del mapa equivalga al menos al padding especificado. Ten en cuenta que los valores de inclinación y rumbo del mapa se fijarán en 0.

Java

LatLngBounds australiaBounds = new LatLngBounds(
    new LatLng(-44, 113), // SW bounds
    new LatLng(-10, 154)  // NE bounds
);
map.moveCamera(CameraUpdateFactory.newLatLngBounds(australiaBounds, 0));
      

Kotlin

val australiaBounds = LatLngBounds(
    LatLng((-44.0), 113.0),  // SW bounds
    LatLng((-10.0), 154.0) // NE bounds
)
map.moveCamera(CameraUpdateFactory.newLatLngBounds(australiaBounds, 0))
      

Cómo centrar el mapa dentro de un área

En algunos casos, probablemente te convenga centrar la cámara dentro de un límite en lugar de incluir los bordes extremos. Puedes hacerlo, por ejemplo, para centrar la cámara en un país y, al mismo tiempo, mantener un zoom constante. En este caso, puedes usar un método similar si creas un objeto LatLngBounds y usas CameraUpdateFactory.newLatLngZoom(LatLng latLng, float zoom) con el método LatLngBounds.getCenter(). El método getCenter() mostrará el centro geográfico de LatLngBounds.

Java

LatLngBounds australiaBounds = new LatLngBounds(
    new LatLng(-44, 113), // SW bounds
    new LatLng(-10, 154)  // NE bounds
);
map.moveCamera(CameraUpdateFactory.newLatLngZoom(australiaBounds.getCenter(), 10));
      

Kotlin

val australiaBounds = LatLngBounds(
    LatLng((-44.0), 113.0),  // SW bounds
    LatLng((-10.0), 154.0) // NE bounds
)
map.moveCamera(CameraUpdateFactory.newLatLngZoom(australiaBounds.center, 10f))
      

Una sobrecarga del método newLatLngBounds(boundary, width, height, padding) te permite especificar un ancho y una altura en píxeles para un rectángulo, con la intención de que estos se correspondan con las dimensiones del mapa. El rectángulo se posiciona de modo que su centro sea idéntico al de la vista del mapa (de esta manera, si las dimensiones especificadas son idénticas a las de la vista del mapa, el rectángulo coincidirá con la visión del mapa). El objeto CameraUpdate que se muestra moverá la cámara de modo que los objetos LatLngBounds especificados se centren en la pantalla dentro del rectángulo determinado con el máximo nivel de zoom posible, teniendo en cuenta el padding requerido.

Nota: Usa el método más simple newLatLngBounds(boundary, padding) para generar un objeto CameraUpdate solo si este se empleará para mover la cámara una vez que se haya aplicado diseño al mapa. Durante la aplicación del diseño, la API calcula los límites de visualización del mapa que se necesitan para proyectar de manera correcta el cuadro de límite. En cambio, puedes usar el objeto CameraUpdate que muestra el método más complejo newLatLngBounds(boundary, width, height, padding) en cualquier momento, aun antes de que se aplique diseño al mapa, ya que la API calcula los límites de visualización a partir de los argumentos que pases.

Cómo restringir el desplazamiento lateral del usuario en un área determinada

En las situaciones antes mencionadas, se fijan los límites del mapa, pero el usuario se puede desplazar vertical o lateralmente por fuera de estos límites. Como alternativa, podrías restringir los límites centrales de latitud y longitud del punto focal del mapa (objetivo de la cámara) para que los usuarios solo puedan desplazarse vertical y lateralmente dentro de estos límites. Por ejemplo, en una app minorista para un centro comercial o un aeropuerto, podrías restringir el mapa a determinados límites, de modo que los usuarios puedan desplazarse vertical y lateralmente dentro de dichos límites.

Java

// Create a LatLngBounds that includes the city of Adelaide in Australia.
LatLngBounds adelaideBounds = new LatLngBounds(
    new LatLng(-35.0, 138.58), // SW bounds
    new LatLng(-34.9, 138.61)  // NE bounds
);

// Constrain the camera target to the Adelaide bounds.
map.setLatLngBoundsForCameraTarget(adelaideBounds);
      

Kotlin

// Create a LatLngBounds that includes the city of Adelaide in Australia.
val adelaideBounds = LatLngBounds(
    LatLng(-35.0, 138.58),  // SW bounds
    LatLng(-34.9, 138.61) // NE bounds
)

// Constrain the camera target to the Adelaide bounds.
map.setLatLngBoundsForCameraTarget(adelaideBounds)
      

En el siguiente diagrama, se ilustra una situación en la cual el objetivo de la cámara está restringido a un área ligeramente más grande que el viewport. El usuario puede desplazarse vertical o lateralmente, siempre que el objetivo de la cámara permanezca dentro del área limitada. La cruz representa el objetivo de la cámara:

Diagrama que muestra límites LatLngBounds de cámara más grandes que el viewport

El mapa siempre ocupa por completo el viewport, incluso aunque se terminen mostrando áreas que se encuentren fuera de los límites definidos. Por ejemplo, si ubicas el objetivo de tu cámara en una esquina del área limitada, el área más allá de la esquina se puede ver en el viewport, pero los usuarios no se pueden desplazar hacia ella. En el siguiente diagrama, se ilustra esta situación. La cruz representa el objetivo de la cámara:

Diagrama que muestra el objetivo de la cámara en la esquina inferior derecha de los límites LatLngBounds de la cámara

En el siguiente diagrama, el objetivo de la cámara tiene límites muy restringidos, lo cual ofrece al usuario muy pocas oportunidades de desplazamiento vertical o lateral en el mapa. La cruz representa el objetivo de la cámara:

Diagrama que muestra límites LatLngBounds de la cámara menores que el viewport

Cómo actualizar la vista de la cámara

Para aplicar un objeto CameraUpdate al mapa, puedes mover la cámara al instante o animarla de forma fluida. Para mover la cámara al instante con el objeto CameraUpdate proporcionado, puedes llamar a GoogleMap.moveCamera(CameraUpdate).

Para hacer que la experiencia del usuario sea más agradable, especialmente para movimientos cortos, puedes animar el cambio. Para ello, en lugar de llamar a GoogleMap.moveCamera, llama a GoogleMap.animateCamera. El mapa se moverá de forma fluida conforme a los nuevos atributos. La forma más detallada de este método, GoogleMap.animateCamera(cameraUpdate, duration, callback), ofrece tres argumentos:

cameraUpdate
Es el objeto CameraUpdate que describe hacia dónde mover la cámara
.
callback
Es un objeto que implementa GoogleMap.CancellableCallback. Esta interfaz para administrar tareas generalizada define dos métodos: "onCancel()" y "onFinished()". En el caso de la animación, se llama a los métodos en las siguientes circunstancias:
onFinish()
Se invoca si la animación se completa sin interrupciones.
onCancel()

Se invoca si la animación se interrumpe llamando a stopAnimation() o iniciando un nuevo movimiento de la cámara.

Como alternativa, esto también puede ocurrir si llamas a GoogleMap.stopAnimation().

duration
Es la duración deseada de la animación en milisegundos, como un elemento int
.

En los siguientes fragmentos de código, se ilustran algunas de las formas comunes de mover la cámara.

Java

LatLng sydney = new LatLng(-33.88,151.21);
LatLng mountainView = new LatLng(37.4, -122.1);

// Move the camera instantly to Sydney with a zoom of 15.
map.moveCamera(CameraUpdateFactory.newLatLngZoom(sydney, 15));

// Zoom in, animating the camera.
map.animateCamera(CameraUpdateFactory.zoomIn());

// Zoom out to zoom level 10, animating with a duration of 2 seconds.
map.animateCamera(CameraUpdateFactory.zoomTo(10), 2000, null);

// Construct a CameraPosition focusing on Mountain View and animate the camera to that position.
CameraPosition cameraPosition = new CameraPosition.Builder()
    .target(mountainView )      // Sets the center of the map to Mountain View
    .zoom(17)                   // Sets the zoom
    .bearing(90)                // Sets the orientation of the camera to east
    .tilt(30)                   // Sets the tilt of the camera to 30 degrees
    .build();                   // Creates a CameraPosition from the builder
map.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
      

Kotlin

val sydney = LatLng(-33.88, 151.21)
val mountainView = LatLng(37.4, -122.1)

// Move the camera instantly to Sydney with a zoom of 15.
map.moveCamera(CameraUpdateFactory.newLatLngZoom(sydney, 15f))

// Zoom in, animating the camera.
map.animateCamera(CameraUpdateFactory.zoomIn())

// Zoom out to zoom level 10, animating with a duration of 2 seconds.
map.animateCamera(CameraUpdateFactory.zoomTo(10f), 2000, null)

// Construct a CameraPosition focusing on Mountain View and animate the camera to that position.
val cameraPosition = CameraPosition.Builder()
    .target(mountainView) // Sets the center of the map to Mountain View
    .zoom(17f)            // Sets the zoom
    .bearing(90f)         // Sets the orientation of the camera to east
    .tilt(30f)            // Sets the tilt of the camera to 30 degrees
    .build()              // Creates a CameraPosition from the builder
map.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition))