Este codelab es parte del curso Aspectos avanzados de Android en Kotlin. Aprovecharás al máximo este curso si trabajas con los codelabs de forma secuencial, aunque no es obligatorio. Todos los codelabs del curso se indican en la página de destino de los codelabs de Aspectos avanzados de Android en Kotlin.
Crear apps con Google Maps te permite agregar funciones a tu app, como imágenes satelitales, controles de IU sólidos para mapas, seguimiento de ubicaciones y marcadores de ubicación. Puedes agregar valor a Google Maps estándar mostrando información de tu propio conjunto de datos, como las ubicaciones de áreas de pesca o escalada conocidas. También puedes crear juegos en los que el jugador explore el mundo físico, como en una búsqueda del tesoro o incluso en juegos de realidad aumentada.
En esta lección, crearás una app de Google Maps llamada Wander que muestra mapas personalizados y la ubicación del usuario.
Requisitos previos
Conocimiento de lo siguiente:
- Cómo crear una app básica para Android y ejecutarla con Android Studio
- Cómo crear y administrar recursos, como cadenas
- Cómo refactorizar código y cambiar el nombre de las variables con Android Studio
- Cómo usar un mapa de Google como usuario
- Cómo establecer permisos de tiempo de ejecución
Qué aprenderás
- Cómo obtener una clave de API de Google API Console y registrarla en tu app
- Cómo integrar un mapa de Google en tu app
- Cómo mostrar diferentes tipos de mapas
- Cómo darle estilo al mapa de Google
- Cómo agregar marcadores a tu mapa
- Cómo permitir que el usuario coloque un marcador en un lugar de interés (POI)
- Cómo habilitar el seguimiento de la ubicación
- Cómo crear la app de
Wander
, que tiene un mapa de Google integrado - Cómo crear funciones personalizadas para tu app, como marcadores y diseño
- Cómo habilitar el seguimiento de la ubicación en tu app
En este codelab, crearás la app de Wander
, que muestra un mapa de Google Maps con diseño personalizado. La app de Explorar te permite colocar marcadores en ubicaciones, agregar superposiciones y ver tu ubicación en tiempo real.
El SDK de Maps para Android requiere una clave de API. Para obtener la clave de API, registra tu proyecto en la página de API y servicios. La clave de API está vinculada a un certificado digital que asocia la app con su autor. Para obtener más información sobre el uso de certificados digitales y la firma de tu app, consulta Cómo firmar tu app.
En este codelab, usarás la clave de API para el certificado de depuración. El certificado de depuración no es seguro por diseño, como se describe en Firma tu compilación de depuración. Las apps para Android publicadas que usan el SDK de Maps para Android requieren una segunda clave de API: la clave del certificado de lanzamiento. Para obtener más información sobre cómo obtener un certificado de lanzamiento, consulta Obtén una clave de API.
Android Studio incluye una plantilla de actividad de Google Maps que genera código de plantilla útil. El código de la plantilla incluye un archivo google_maps_api.xml que contiene un vínculo que simplifica la obtención de una clave de API.
Paso 1: Crea el proyecto de Wander con la plantilla de mapas
- Crea un proyecto nuevo de Android Studio.
- Selecciona la plantilla Google Maps Activity.
- Asigna el nombre
Wander
al proyecto. - Establece el nivel de API mínimo en API 19. Asegúrate de que el lenguaje sea Kotlin.
- Haz clic en Finalizar.
- Una vez que se termine de compilar la app, observa tu proyecto y los siguientes archivos relacionados con mapas que Android Studio crea para ti:
google_maps_api.xml: Usas este archivo de configuración para almacenar tu clave de API. La plantilla genera dos archivos google_maps_api.xml: uno para la depuración y otro para el lanzamiento. El archivo de la clave de API del certificado de depuración se encuentra en src/debug/res/values. El archivo de la clave de API del certificado de lanzamiento se encuentra en src/release/res/values. En este codelab, solo usarás el certificado de depuración.
activity_maps.xml: Este archivo de diseño contiene un solo fragmento que ocupa toda la pantalla. La clase SupportMapFragment
es una subclase de la clase Fragment
. Un SupportMapFragment
es la forma más sencilla de colocar un mapa en una app. Es un wrapper alrededor de una vista de un mapa para controlar automáticamente las necesidades del ciclo de vida necesarias.
Puedes incluir SupportMapFragment
en un archivo de diseño con una etiqueta <fragment>
en cualquier ViewGroup
, con un atributo name
adicional.
android:name="com.google.android.gms.maps.SupportMapFragment"
MapsActivity.java: El archivo MapsActivity.kt crea una instancia de SupportMapFragment
en el método onCreate()
y usa el getMapAsync
()
de la clase para inicializar automáticamente el sistema de mapas y la vista. La actividad que contiene el SupportMapFragment
debe implementar la interfaz OnMapReadyCallback
y el método onMapReady()
de esa interfaz. Se llama al método onMapReady()
cuando se carga el mapa.
Paso 2: Obtén la clave de API
- Abre la versión de depuración del archivo google_maps_api.xml.
- En el archivo, busca un comentario con una URL larga. Los parámetros de la URL incluyen información específica sobre tu app.
- Copia y pega la URL en un navegador.
- Sigue las indicaciones para crear un proyecto en la página de APIs y servicios. Debido a los parámetros de la URL proporcionada, la página sabe que debe habilitar automáticamente el SDK de Maps para Android.
- Haz clic en Crear una clave de API.
- En la página siguiente, ve a la sección Claves de API y haz clic en la clave que acabas de crear.
- Haz clic en Restringir clave y selecciona SDK de Maps para Android para restringir el uso de la clave a las apps para Android.
- Copia la clave de API generada. Comienza con "
AIza"
. - En el archivo
google_maps_api.xml
, pega la clave en la cadenagoogle_maps_key
donde diceYOUR_KEY_HERE
. - Ejecuta tu app. Deberías ver un mapa incorporado en tu actividad con un marcador establecido en Sídney, Australia. (El marcador de Sídney forma parte de la plantilla y lo cambiarás más adelante).
Paso 3: Cambia el nombre de mMap
MapsActivity
tiene un lateinit
var
privado llamado mMap
, que es de tipo GoogleMap
. Para seguir las convenciones de nomenclatura de Kotlin, cambia el nombre de mMap
a map
.
- En
MapsActivity
, haz clic con el botón derecho enmMap
y, luego, en Refactor > Rename…
- Cambia el nombre de la variable a
map
.
Observa cómo todas las referencias a mMap
en la función onMapReady()
también cambian a map
.
Google Maps incluye varios tipos de mapas: normal, híbrido, satelital, de terreno y "ninguno" (para no mostrar ningún mapa).
Mapa normal | Mapa satelital | Mapa híbrido | Mapa de terreno |
Cada tipo de mapa proporciona diferentes tipos de información. Por ejemplo, cuando usas mapas para navegar en un automóvil, es útil ver los nombres de las calles, por lo que podrías usar la opción normal. Cuando haces senderismo, el mapa de terreno puede ser útil para decidir cuánto más debes subir para llegar a la cima.
En esta tarea, harás lo siguiente:
- Agrega una barra de la aplicación con un menú de opciones que le permita al usuario cambiar el tipo de mapa.
- Mueve la ubicación inicial del mapa a la ubicación de tu casa.
- Se agregó compatibilidad con marcadores, que indican ubicaciones únicas en un mapa y pueden incluir una etiqueta.
Menú para agregar tipos de mapas
En este paso, agregarás una barra de la app con un menú de opciones que le permita al usuario cambiar el tipo de mapa.
- Para crear un nuevo archivo XML de menú, haz clic con el botón derecho en el directorio res y selecciona New > Android Resource File.
- En el diálogo, asigna el nombre
map_options
al archivo. - Elige Menú para el tipo de recurso.
- Haz clic en Aceptar.
- En la pestaña Code, reemplaza el código del archivo nuevo por el siguiente código para crear las opciones del menú del mapa. Se omite el tipo de mapa "none" porque "none" genera la ausencia de cualquier mapa. Este paso genera un error, pero lo resolverás en el siguiente.
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/normal_map"
android:title="@string/normal_map"
app:showAsAction="never" />
<item
android:id="@+id/hybrid_map"
android:title="@string/hybrid_map"
app:showAsAction="never" />
<item
android:id="@+id/satellite_map"
android:title="@string/satellite_map"
app:showAsAction="never" />
<item
android:id="@+id/terrain_map"
android:title="@string/terrain_map"
app:showAsAction="never" />
</menu>
- En
strings.xml
, agrega recursos para los atributostitle
y, así, resolver los errores.
<resources>
...
<string name="normal_map">Normal Map</string>
<string name="hybrid_map">Hybrid Map</string>
<string name="satellite_map">Satellite Map</string>
<string name="terrain_map">Terrain Map</string>
<string name="lat_long_snippet">Lat: %1$.5f, Long: %2$.5f</string>
<string name="dropped_pin">Dropped Pin</string>
<string name="poi">poi</string>
</resources>
- En
MapsActivity
, anula el métodoonCreateOptionsMenu()
y aumenta el menú desde el archivo de recursosmap_options
.
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
val inflater = menuInflater
inflater.inflate(R.menu.map_options, menu)
return true
}
- En
MapsActivity.kt
, anula el métodoonOptionsItemSelected()
. Cambia el tipo de mapa con constantes de tipo de mapa para reflejar la selección del usuario.
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
// Change the map type based on the user's selection.
R.id.normal_map -> {
map.mapType = GoogleMap.MAP_TYPE_NORMAL
true
}
R.id.hybrid_map -> {
map.mapType = GoogleMap.MAP_TYPE_HYBRID
true
}
R.id.satellite_map -> {
map.mapType = GoogleMap.MAP_TYPE_SATELLITE
true
}
R.id.terrain_map -> {
map.mapType = GoogleMap.MAP_TYPE_TERRAIN
true
}
else -> super.onOptionsItemSelected(item)
}
- Ejecuta la app.
- Haz clic en
para cambiar el tipo de mapa. Observa cómo cambia la apariencia del mapa entre los diferentes modos.
De forma predeterminada, la devolución de llamada onMapReady()
incluye código que coloca un marcador en Sídney, Australia, donde se creó Google Maps. La devolución de llamada predeterminada también anima el mapa para que se desplace a Sídney.
En esta tarea, harás que la cámara del mapa se mueva a tu casa, se acerque a un nivel que especifiques y coloque un marcador allí.
Paso 1: Acercar la vista a tu casa y agregar un marcador
- En el archivo
MapsActivity.kt
, busca el métodoonMapReady()
. Quita el código que coloca el marcador en Sídney y mueve la cámara. Así debería verse tu método ahora.
override fun onMapReady(googleMap: GoogleMap) {
map = googleMap
}
- Sigue estas instrucciones para encontrar la latitud y la longitud de tu casa.
- Crea un valor para la latitud y otro para la longitud, y luego ingresa sus valores de punto flotante.
val latitude = 37.422160
val longitude = -122.084270
- Crea un objeto
LatLng
nuevo llamadohomeLatLng
. En el objetohomeLatLng
, pasa los valores que acabas de crear.
val homeLatLng = LatLng(latitude, longitude)
- Crea un
val
para indicar el nivel de acercamiento que deseas tener en el mapa. Usa el nivel de zoom 15f.
val zoomLevel = 15f
El nivel de zoom controla qué tan cerca ves el mapa. En la siguiente lista, se indica el nivel de detalle que se muestra en cada nivel de zoom:
1
: Mundial5
: Tierra firme y continente10
: Ciudad15
: Calles20
: Edificios
- Mueve la cámara a
homeLatLng
llamando a la funciónmoveCamera()
en el objetomap
y pasa un objetoCameraUpdate
conCameraUpdateFactory.newLatLngZoom()
. Pasa el objetohomeLatLng
y elzoomLevel
.
map.moveCamera(CameraUpdateFactory.newLatLngZoom(homeLatLng, zoomLevel))
- Agrega un marcador al mapa en
homeLatLng
.
map.addMarker(MarkerOptions().position(homeLatLng))
El método final debería verse de la siguiente manera:
override fun onMapReady(googleMap: GoogleMap) {
map = googleMap
//These coordinates represent the latitude and longitude of the Googleplex.
val latitude = 37.422160
val longitude = -122.084270
val zoomLevel = 15f
val homeLatLng = LatLng(latitude, longitude)
map.moveCamera(CameraUpdateFactory.newLatLngZoom(homeLatLng, zoomLevel))
map.addMarker(MarkerOptions().position(homeLatLng))
}
- Ejecuta tu app. El mapa debería desplazarse hasta tu casa, acercarse al nivel deseado y colocar un marcador en ella.
Paso 2: Permite que los usuarios agreguen un marcador con un clic largo
En este paso, agregarás un marcador cuando el usuario mantenga presionada una ubicación en el mapa.
- Crea un código auxiliar del método en
MapsActivity
llamadosetMapLongClick()
que tome unGoogleMap
como argumento. - Adjunta un objeto de escucha
setOnMapLongClickListener
al objeto del mapa.
private fun setMapLongClick(map:GoogleMap) {
map.setOnMapLongClickListener { }
}
- En
setOnMapLongClickListener()
, llama al métodoaddMarker()
. Pasa un nuevo objetoMarkerOptions
con la posición establecida en elLatLng
pasado.
private fun setMapLongClick(map: GoogleMap) {
map.setOnMapLongClickListener { latLng ->
map.addMarker(
MarkerOptions()
.position(latLng)
)
}
}
- Al final del método
onMapReady()
, llama asetMapLongClick()
conmap
.
override fun onMapReady(googleMap: GoogleMap) {
...
setMapLongClick(map)
}
- Ejecuta tu app.
- Mantén presionado el mapa para colocar un marcador en una ubicación.
- Presiona el marcador para centrarlo en la pantalla.
Paso 3: Agrega una ventana de información para el marcador
En este paso, agregarás un InfoWindow
que muestra las coordenadas del marcador cuando se presiona.
- En
setMapLongClick()setOnMapLongClickListener()
, crea unval
parasnippet
. Un fragmento es un texto adicional que se muestra después del título. Tu fragmento muestra la latitud y la longitud de un marcador.
private fun setMapLongClick(map: GoogleMap) {
map.setOnMapLongClickListener { latLng ->
// A snippet is additional text that's displayed after the title.
val snippet = String.format(
Locale.getDefault(),
"Lat: %1$.5f, Long: %2$.5f",
latLng.latitude,
latLng.longitude
)
map.addMarker(
MarkerOptions()
.position(latLng)
)
}
}
- En
addMarker()
, configura eltitle
del marcador como Dropped Pin con un recurso de cadenaR.string.
dropped_pin
. - Establece el
snippet
del marcador ensnippet
.
La función completada se ve de la siguiente manera:
private fun setMapLongClick(map: GoogleMap) {
map.setOnMapLongClickListener { latLng ->
// A Snippet is Additional text that's displayed below the title.
val snippet = String.format(
Locale.getDefault(),
"Lat: %1$.5f, Long: %2$.5f",
latLng.latitude,
latLng.longitude
)
map.addMarker(
MarkerOptions()
.position(latLng)
.title(getString(R.string.dropped_pin))
.snippet(snippet)
)
}
}
- Ejecuta tu app.
- Mantén presionado el mapa para colocar un marcador de ubicación.
- Presiona el marcador para mostrar la ventana de información.
Paso 4: Agrega un objeto de escucha de PDI
De forma predeterminada, los lugares de interés aparecen en el mapa junto con sus íconos correspondientes. Los POI incluyen parques, escuelas, edificios gubernamentales y mucho más. Cuando el tipo de mapa se establece en normal
, los POI comerciales también aparecen en el mapa. Los POI comerciales representan empresas, como tiendas, restaurantes y hoteles.
En este paso, agregarás un GoogleMap.OnPoiClickListener
al mapa. Este objeto de escucha de clics coloca un marcador en el mapa inmediatamente cuando el usuario hace clic en un POI. El objeto de escucha de clics también muestra una ventana de información que contiene el nombre del PDI.
- Crea un código auxiliar del método en
MapsActivity
llamadosetPoiClick()
que tome unGoogleMap
como argumento. - En el método
setPoiClick()
, establece unOnPoiClickListener
en elGoogleMap
que se pasó.
private fun setPoiClick(map: GoogleMap) {
map.setOnPoiClickListener { poi ->
}
}
- En
setOnPoiClickListener()
, crea unval poiMarker
para el marcador . - Establécelo en un marcador con
map.addMarker()
yMarkerOptions
para establecertitle
en el nombre del PDI.
private fun setPoiClick(map: GoogleMap) {
map.setOnPoiClickListener { poi ->
val poiMarker = map.addMarker(
MarkerOptions()
.position(poi.latLng)
.title(poi.name)
)
}
}
- En la función
setOnPoiClickListener()
, llama ashowInfoWindow()
enpoiMarker
para mostrar la ventana de información de inmediato.
poiMarker.showInfoWindow()
El código final de la función setPoiClick()
debería verse de la siguiente manera:
private fun setPoiClick(map: GoogleMap) {
map.setOnPoiClickListener { poi ->
val poiMarker = map.addMarker(
MarkerOptions()
.position(poi.latLng)
.title(poi.name)
)
poiMarker.showInfoWindow()
}
}
- Al final de
onMapReady()
, llama asetPoiClick()
y pasamap
.
override fun onMapReady(googleMap: GoogleMap) {
...
setPoiClick(map)
}
- Ejecuta tu app y busca un PDI, como un parque o una cafetería.
- Presiona el PDI para colocar un marcador en él y mostrar su nombre en una ventana de información.
Puedes personalizar Google Maps de muchas maneras para darle a tu mapa un aspecto único.
Puedes personalizar un objeto MapFragment
con los atributos XML disponibles, como lo harías con cualquier otro fragmento. Sin embargo, en este paso, personalizarás la apariencia del contenido de MapFragment
con métodos del objeto GoogleMap
.
Para crear un diseño personalizado para tu mapa, genera un archivo JSON que especifique cómo se muestran los elementos del mapa. No es necesario que crees este archivo JSON de forma manual. Google proporciona el Asistente de diseño de Maps Platform, que genera el código JSON por ti después de que le aplicas un diseño visual a tu mapa. En esta tarea, aplicarás un diseño retro al mapa, lo que significa que el mapa usará colores vintage y agregarás rutas de color.
Paso 1: Crea un diseño para tu mapa
- Navega a https://mapstyle.withgoogle.com/ en tu navegador.
- Selecciona Crear un diseño.
- Selecciona Retro.
- Haz clic en Más opciones.
- En la lista Tipo de función, selecciona Carretera > Relleno.
- Cambia el color de las rutas al que quieras (por ejemplo, rosa).
- Haz clic en Finalizar.
- Copia el código JSON del diálogo resultante y, si lo deseas, guárdalo en una nota de texto sin formato para usarlo en el siguiente paso.
Paso 2: Agrega el diseño a tu mapa
- En Android Studio, en el directorio
res
, crea un directorio de recursos y nómbraloraw
. Usas los recursos del directorioraw
como código JSON. - Crea un archivo en
res/raw
llamadomap_style.json
. - Pega el código JSON almacenado en el nuevo archivo de recursos.
- En
MapsActivity
, crea una variable de claseTAG
sobre el métodoonCreate()
. Se usa para fines de registro.
private val TAG = MapsActivity::class.java.simpleName
- También en
MapsActivity
, crea una funciónsetMapStyle()
que tome unGoogleMap
. - En
setMapStyle()
, agrega un bloquetry{}
. - En el bloque
try{}
, crea unval success
para el éxito del diseño. (Agregarás el siguiente bloque catch). - En el bloque
try{}
, configura el diseño JSON en el mapa y llama asetMapStyle()
en el objetoGoogleMap
. Pasa un objetoMapStyleOptions
, que carga el archivo JSON. - Asigna el resultado a
success
. El métodosetMapStyle()
devuelve un valor booleano que indica el estado de éxito del análisis del archivo de diseño y la configuración del diseño.
private fun setMapStyle(map: GoogleMap) {
try {
// Customize the styling of the base map using a JSON object defined
// in a raw resource file.
val success = map.setMapStyle(
MapStyleOptions.loadRawResourceStyle(
this,
R.raw.map_style
)
)
}
}
- Agrega una sentencia if para
success
que sea falso. Si el diseño no se aplica correctamente, imprime un registro que indique que falló el análisis.
private fun setMapStyle(map: GoogleMap) {
try {
...
if (!success) {
Log.e(TAG, "Style parsing failed.")
}
}
}
- Agrega un bloque
catch{}
para controlar la situación de un archivo de diseño faltante. En el bloquecatch
, si no se puede cargar el archivo, arroja unResources.NotFoundException
.
private fun setMapStyle(map: GoogleMap) {
try {
...
} catch (e: Resources.NotFoundException) {
Log.e(TAG, "Can't find style. Error: ", e)
}
}
El método finalizado debería verse como el siguiente fragmento de código:
private fun setMapStyle(map: GoogleMap) {
try {
// Customize the styling of the base map using a JSON object defined
// in a raw resource file.
val success = map.setMapStyle(
MapStyleOptions.loadRawResourceStyle(
this,
R.raw.map_style
)
)
if (!success) {
Log.e(TAG, "Style parsing failed.")
}
} catch (e: Resources.NotFoundException) {
Log.e(TAG, "Can't find style. Error: ", e)
}
}
- Por último, llama al método
setMapStyle()
en el métodoonMapReady()
y pasa tu objetoGoogleMap
.
override fun onMapReady(googleMap: GoogleMap) {
...
setMapStyle(map)
}
- Ejecuta tu app.
- Establece el mapa en el modo
normal
y el nuevo diseño debería ser visible con el tema retro y las rutas del color que elegiste.
Paso 3: Aplica estilo a tu marcador
Puedes personalizar aún más tu mapa aplicando un diseño a los marcadores. En este paso, cambiarás los marcadores rojos predeterminados por algo más genial.
- En el método
onMapLongClick()
, agrega la siguiente línea de código alMarkerOptions()
del constructor para usar el marcador predeterminado, pero cambia el color a azul.
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE))
Ahora, onMapLongClickListener()
se ve de la siguiente manera:
map.setOnMapLongClickListener { latLng ->
// A snippet is additional text that's displayed after the title.
val snippet = String.format(
Locale.getDefault(),
"Lat: %1$.5f, Long: %2$.5f",
latLng.latitude,
latLng.longitude
)
map.addMarker(
MarkerOptions()
.position(latLng)
.title(getString(R.string.dropped_pin))
.snippet(snippet)
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE))
)
}
- Ejecuta la app. Los marcadores que aparecen después de que haces un clic largo ahora están sombreados en azul. Ten en cuenta que los marcadores de POI siguen siendo rojos porque no agregaste diseño al método
onPoiClick()
.
Una forma de personalizar el mapa de Google es dibujar sobre él. Esta técnica es útil si deseas destacar un tipo de ubicación en particular, como los lugares de pesca populares.
- Formas: Puedes agregar polilíneas, polígonos y círculos al mapa.
- Objetos
GroundOverlay
: Una superposición de suelo es una imagen que se fija a un mapa. A diferencia de los marcadores, las superposiciones de suelo se orientan hacia la superficie de la Tierra, en lugar de hacia la pantalla. La rotación, la inclinación o el zoom del mapa cambian la orientación de la imagen. Las superposiciones de suelo resultan útiles cuando deseas fijar una sola imagen en un área del mapa.
Paso: Agrega una superposición de suelo
En esta tarea, agregarás una superposición de tierra en forma de Android a la ubicación de tu casa.
- Descarga esta imagen de Android y guárdala en tu carpeta
res/drawable
. (Asegúrate de que el nombre del archivo seaandroid.png
).
- En
onMapReady()
, después de la llamada para mover la cámara a la posición de tu casa, crea un objetoGroundOverlayOptions
. - Asigna el objeto a una variable llamada
androidOverlay
.
val androidOverlay = GroundOverlayOptions()
- Usa el método
BitmapDescriptorFactory.fromResource()
para crear un objetoBitmapDescriptor
a partir del recurso de imagen descargado. - Pasa el objeto
BitmapDescriptor
resultante al métodoimage()
del objetoGroundOverlayOptions
.
val androidOverlay = GroundOverlayOptions()
.image(BitmapDescriptorFactory.fromResource(R.drawable.android))
- Crea un
float overlaySize
para el ancho en metros de la superposición deseada. Para este ejemplo, un ancho de100f
funciona bien.
Configura la propiedad position
para el objeto GroundOverlayOptions
llamando al método position()
y pasa el objeto homeLatLng
y el overlaySize
.
val overlaySize = 100f
val androidOverlay = GroundOverlayOptions()
.image(BitmapDescriptorFactory.fromResource(R.drawable.android))
.position(homeLatLng, overlaySize)
- Llama a
addGroundOverlay()
en el objetoGoogleMap
y pasa tu objetoGroundOverlayOptions
.
map.addGroundOverlay(androidOverlay)
- Ejecuta la app.
- Cambia el valor de
zoomLevel
a 18f para ver la imagen de Android como una superposición.
Los usuarios suelen usar Google Maps para ver su ubicación actual. Para mostrar la ubicación del dispositivo en tu mapa, puedes usar la capa de datos de ubicación.
La capa de datos de ubicación agrega Mi ubicación al mapa. Cuando el usuario presiona el botón, el mapa se centra en la ubicación del dispositivo. La ubicación se muestra como un punto azul si el dispositivo está quieto y como una comilla angular azul si está en movimiento.
En esta tarea, habilitarás la capa de datos de ubicación.
Paso: Solicita permisos de ubicación
Para habilitar el rastreo de la ubicación en Google Maps, se requiere una sola línea de código. Sin embargo, debes asegurarte de que el usuario haya otorgado permisos de ubicación (con el modelo de permisos de tiempo de ejecución).
En este paso, solicitarás permisos de ubicación y habilitarás el seguimiento de la ubicación.
- En el archivo
AndroidManifest.xml
, verifica que el permisoFINE_LOCATION
ya esté presente. Android Studio insertó este permiso cuando seleccionaste la plantilla de Google Maps.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
- En
MapsActivity
, crea una variable de claseREQUEST_LOCATION_PERMISSION
.
private val REQUEST_LOCATION_PERMISSION = 1
- Para verificar si se otorgaron permisos, crea un método en
MapsActivity
llamadoisPermissionGranted()
. En este método, verifica si el usuario otorgó el permiso.
private fun isPermissionGranted() : Boolean {
return ContextCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
}
- Para habilitar el seguimiento de la ubicación en tu app, crea un método en
MapsActivity
llamadoenableMyLocation()
que no tome argumentos y no muestre nada. Dentro, busca el permisoACCESS_FINE_LOCATION
. Si se otorga el permiso, habilita la capa de ubicación. De lo contrario, solicita el permiso.
private fun enableMyLocation() {
if (isPermissionGranted()) {
map.isMyLocationEnabled = true
}
else {
ActivityCompat.requestPermissions(
this,
arrayOf<String>(Manifest.permission.ACCESS_FINE_LOCATION),
REQUEST_LOCATION_PERMISSION
)
}
}
- Llama a
enableMyLocation()
desde la devolución de llamadaonMapReady()
para habilitar la capa de ubicación.
override fun onMapReady(googleMap: GoogleMap) {
...
enableMyLocation()
}
- Anula el método
onRequestPermissionsResult()
. Si el permiso derequestCode
es igual aREQUEST_LOCATION_PERMISSION
, y si el array degrantResults
no está vacío y tienePackageManager.PERMISSION_GRANTED
en su primer espacio, llama aenableMyLocation()
.
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray) {
if (requestCode == REQUEST_LOCATION_PERMISSION) {
if (grantResults.contains(PackageManager.PERMISSION_GRANTED)) {
enableMyLocation()
}
}
}
- Ejecuta tu app. Debería aparecer un diálogo que solicite acceso a la ubicación del dispositivo. Continúa y permite el permiso.
Ahora, el mapa muestra la ubicación actual del dispositivo con un punto azul. Observa que hay un botón de ubicación. Si alejas el mapa de tu ubicación y haces clic en este botón, el mapa se centrará nuevamente en la ubicación del dispositivo.
Descarga el código del codelab terminado.
$ git clone https://github.com/googlecodelabs/android-kotlin-geo-maps
También puedes descargar el repositorio como un archivo ZIP, descomprimirlo y abrirlo en Android Studio.
- Para usar la API de Maps, necesitas una clave de API de la Consola de APIs de Google.
- En Android Studio, usar la plantilla de Google Maps Activity genera un
Activity
con un soloSupportMapFragment
en el diseño de la app. La plantilla también agregaACCESS_FINE_PERMISSION
al manifiesto de la app, implementaOnMapReadyCallback
en tu actividad y anula el métodoonMapReady()
requerido.
Para cambiar el tipo de mapa de un objeto GoogleMap
durante el tiempo de ejecución, usa el método GoogleMap.setMapType()
. Un mapa de Google puede ser uno de los siguientes tipos de mapas:
- Normal: Es un mapa de ruta típico. Muestra rutas, algunos elementos creados por el hombre y elementos naturales importantes, como ríos. También muestra etiquetas de rutas y elementos.
- Híbrido: Muestra datos de fotos satelitales, además de los mapas de ruta. También muestra etiquetas de rutas y elementos.
- Satélite: Datos de fotografías No se ven etiquetas de carreteras y elementos.
- Terreno: Muestra datos topográficos. El mapa incluye colores, isolíneas y etiquetas relacionadas, y sombras que agregan perspectiva. También muestra algunas rutas y etiquetas.
- None: No hay mosaicos del mapa base.
Acerca de Google Maps:
- Un marcador es un indicador de una ubicación geográfica específica.
- Cuando se presiona, el comportamiento predeterminado del marcador es mostrar una ventana de información con datos sobre la ubicación.
- De forma predeterminada, los puntos de interés (POI) aparecen en el mapa básico con sus íconos correspondientes. Los POI incluyen parques, escuelas, edificios gubernamentales y mucho más.
- Además, los POI comerciales (tiendas, restaurantes, hoteles y mucho más) aparecen de forma predeterminada en el mapa cuando el tipo de mapa es
normal
. - Puedes capturar clics en los POIs con
OnPoiClickListener
. - Puedes cambiar la apariencia visual de casi todos los elementos de un mapa de Google con el Asistente de diseño. El asistente de diseño genera un archivo JSON que pasas al mapa de Google con el método
setMapStyle()
. - Puedes personalizar tus marcadores cambiando el color predeterminado o reemplazando el ícono predeterminado del marcador por una imagen personalizada.
Otra información importante:
- Usa una superposición de suelo para fijar una imagen a una ubicación geográfica.
- Usa un objeto
GroundOverlayOptions
para especificar la imagen, su tamaño en metros y su posición. Pasa este objeto al métodoGoogleMap.addGroundOverlay()
para establecer la superposición en el mapa. - Siempre que tu app tenga el permiso
ACCESS_FINE_LOCATION
, puedes habilitar el seguimiento de la ubicación configurandomap.isMyLocationEnabled = true
. - No se aborda en este codelab, pero puedes proporcionar información adicional sobre una ubicación con Google Street View, que es una foto panorámica navegable de una ubicación determinada.
Documentación para desarrolladores de Android:
- Comenzar
- Cómo agregar un mapa con un marcador
- Objetos de mapas
- Cómo agregar un mapa con diseños
- Street View
- Superposiciones de suelo
Documentación de referencia:
Para obtener vínculos a otros codelabs de este curso, consulta la página de destino de los codelabs de Aspectos avanzados de Android en Kotlin.