Skip to content

Tutorial

Tutorial de MapConductor

En este tutorial aprenderás a usar MapConductor Android SDK para mostrar un mapa, añadir marcadores y figuras, y manejar interacciones de usuario.

Qué aprenderás

  • Cómo instalar y configurar el SDK de MapConductor
  • Cómo mostrar un mapa
  • Cómo añadir marcadores, círculos y polilíneas
  • Cómo manejar eventos de tap/clic
  • Cómo controlar la posición de la cámara
  • Cómo cambiar entre distintos SDK de mapas

Requisitos previos

  • Android Studio instalado
  • Conocimientos básicos de Jetpack Compose
  • Conocimientos básicos de Kotlin

Paso 1: Configuración del proyecto

1-1. Añadir dependencias

Añade las dependencias de MapConductor en build.gradle.kts o build.gradle del módulo:

dependencies {
val mapconductorVersion = "1.1.7"
// Usar BOM para unificar versiones
implementation(platform("com.mapconductor:mapconductor-bom:$mapconductorVersion"))
// Módulo principal (requerido)
implementation("com.mapconductor:core")
// Si utilizas Google Maps
implementation("com.mapconductor:for-googlemaps")
// O si utilizas Mapbox
// implementation("com.mapconductor:for-mapbox")
// O si utilizas HERE Maps
// implementation("com.mapconductor:for-here")
// O si utilizas ArcGIS
// implementation("com.mapconductor:for-arcgis")
// O si utilizas MapLibre
// implementation("com.mapconductor:for-maplibre")
}

1-2. Configuración de Android

Añade la siguiente configuración en build.gradle.kts o build.gradle:

plugin {
id("org.jetbrains.kotlin.plugin.compose:2.4.0")
id("org.jetbrains.kotlin.android:2.4.0")
}
android {
compileSdk = 37
defaultConfig {
minSdk = 26
targetSdk = 37
}
buildFeatures {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion =
project.property("2.4.0").toString()
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "17"
}
}

1-3. Configuración del SDK de mapas

Importante: MapConductor proporciona una capa de API unificada sobre los SDK de mapas existentes. Antes de usar MapConductor, debes configurar cada SDK de mapas individualmente.

Cada SDK de mapas requiere sus propias claves API, permisos y configuración:

Paso 2: Mostrar un mapa simple

Empecemos con la forma más simple de mostrar un mapa centrado en Tokio.

import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.mapconductor.core.GeoPoint
import com.mapconductor.core.MapCameraPosition
import com.mapconductor.googlemaps.GoogleMapView
import com.mapconductor.googlemaps.rememberGoogleMapViewState
@Composable
fun MyFirstMap(modifier: Modifier = Modifier) {
// Coordenadas de Tokio
val tokyo = GeoPoint.fromLatLong(35.6812, 139.7671)
// Posición inicial de la cámara
val initialCamera = MapCameraPosition(
position = tokyo,
zoom = 12
)
// Gestión de estado
val mapViewState = rememberGoogleMapViewState(
cameraPosition = initialCamera
)
// Mostrar mapa
GoogleMapView(
modifier = modifier,
state = mapViewState
)
}

Resultado del mapa Nota: El estilo de demostración se ha modificado del predeterminado para mayor claridad

¡Eso es! Ahora tienes un mapa centrado en Tokio mostrado en tu aplicación.

Paso 3: Añadir marcadores

Añadamos marcadores al mapa.

import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.mapconductor.core.*
import com.mapconductor.googlemaps.GoogleMapView
import com.mapconductor.googlemaps.rememberGoogleMapViewState
@Composable
fun MapWithMarkers(modifier: Modifier = Modifier) {
// Coordenadas
val marker1 = GeoPoint.fromLatLong(35.6586, 139.7454)
val marker2 = GeoPoint.fromLatLong(35.7101, 139.8107)
// Posición inicial
val initialCamera = MapCameraPosition(
position = GeoPoint.fromLatLong(35.6586, 139.7454),
zoom = 11
)
val mapViewState = rememberGoogleMapViewState(
cameraPosition = initialCamera
)
val onMarkerClick: (MarkerState) -> Unit = { markerState ->
println("Manejar clic en marcador${markerState.extra}")
}
GoogleMapView(
modifier = modifier.fillMaxSize(),
state = mapViewState
) {
// Añadir marcadores
Marker(
position = marker1,
icon = ColorDefaultIcon(label = "Tokyo Tower"),
extra = "marker1",
onClick = onMarkerClick
)
Marker(
position = marker2,
icon = ColorDefaultIcon(label = "Sky Tree"),
extra = "marker2",
onClick = onMarkerClick
)
}
}

Mapa con marcadores Nota: El estilo de demostración se ha modificado del predeterminado para mayor claridad

Personalizar marcadores

Puedes personalizar marcadores con colores y estilos:

Marker(
position = GeoPoint.fromLatLong(35.6586, 139.7454),
icon = ColorDefaultIcon(
label = "TT",
backgroundColor = Color.Red,
textColor = Color.White
),
extra = "tokyo_tower",
anchor = Offset(0.5f, 1.0f) // Información de anclaje
)

Paso 4: Añadir círculos y polilíneas

4-1. Añadir círculos

Dibujemos un círculo alrededor de un marcador.

import androidx.compose.ui.graphics.Color
GoogleMapView(
modifier = modifier.fillMaxSize(),
state = mapViewState
) {
// Marcador
Marker(
position = GeoPoint.fromLatLong(35.6586, 139.7454),
icon = ColorDefaultIcon(label = "TT"),
extra = "tokyo_tower"
)
// Dibujar círculo
Circle(
center = GeoPoint.fromLatLong(35.6586, 139.7454),
radiusMeters = 1000, // Radio (metros)
strokeColor = Color.Blue,
strokeWidth = 3.dp, // Ancho de trazo (dp)
fillColor = Color.Blue.copy(alpha = 0.2f)
)
}

Marcador con círculo Nota: El estilo de demostración se ha modificado del predeterminado para mayor claridad

4-2. Añadir polilíneas

Ahora dibujemos una línea que conecte dos puntos.

GoogleMapView(
modifier = modifier.fillMaxSize(),
state = mapViewState
) {
// Marcadores
Marker(position = GeoPoint.fromLatLong(35.6586, 139.7454), icon = ColorDefaultIcon(label = "TT"))
Marker(position = GeoPoint.fromLatLong(35.7101, 139.8107), icon = ColorDefaultIcon(label = "ST"))
// Dibujar línea
Polyline(
points = listOf(
GeoPoint.fromLatLong(35.6586, 139.7454),
GeoPoint.fromLatLong(35.7101, 139.8107)
),
strokeColor = Color.Red,
strokeWidth = 5.dp
)
}

Marcador con polilínea Nota: El estilo de demostración se ha modificado del predeterminado para mayor claridad

Paso 5: Manejar interacciones de usuario

5-1. Eventos de clic en el mapa

Puedes manejar cuándo los usuarios tocan el mapa:

import androidx.compose.runtime.*
@Composable
fun InteractiveMap(modifier: Modifier = Modifier) {
var clickedPosition by remember { mutableStateOf<GeoPointInterface?>(null) }
val initialCamera = MapCameraPosition(
position = GeoPoint.fromLatLong(35.6812, 139.7671),
zoom = 12
)
val mapViewState = rememberGoogleMapViewState(
cameraPosition = initialCamera
)
GoogleMapView(
modifier = modifier.fillMaxSize(),
state = mapViewState,
onMapClick = { geoPoint ->
// Mapa tocado
clickedPosition = geoPoint
println("Posición tocada${geoPoint.latitude}, ${geoPoint.longitude}")
}
) {
// Mostrar marcador
clickedPosition?.let { position ->
Marker(
position = position,
icon = ColorDefaultIcon(label = "!"),
extra = "clicked_marker"
)
}
}
}

Nota: El estilo de demostración se ha modificado del predeterminado para mayor claridad

5-2. Eventos de clic en marcadores

Maneja clics en marcadores y dispara animaciones:

val marker1 = GeoPoint.fromLatLong(35.6586, 139.7454)
val marker2 = GeoPoint.fromLatLong(35.7101, 139.8107)
GoogleMapView(
modifier = modifier.fillMaxSize(),
state = mapViewState
) {
Marker(
position = marker1,
icon = ColorDefaultIcon(label = "TT"),
extra = "marker1",
onClick = { markerState ->
// Manejar clic en marcador
markerState.animate(MarkerAnimation.Drop)
}
)
Marker(
position = marker2,
icon = ColorDefaultIcon(label = "ST"),
extra = "marker2",
onClick = { markerState ->
// Manejar clic en marcador
markerState.animate(MarkerAnimation.Bounce)
}
)
}

Nota: El estilo de demostración se ha modificado del predeterminado para mayor claridad

Paso 6: Controlar la cámara

6-1. Mover la cámara a una ubicación específica

Usa botones para mover la cámara a diferentes ubicaciones:

import androidx.compose.foundation.layout.*
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.rememberCoroutineScope
import kotlinx.coroutines.launch
@Composable
fun MapWithCameraControl(modifier: Modifier = Modifier) {
val marker1 = GeoPoint.fromLatLong(35.6586, 139.7454)
val marker2 = GeoPoint.fromLatLong(35.7101, 139.8107)
val mapViewState = rememberGoogleMapViewState(
cameraPosition = MapCameraPosition(
position = marker1,
zoom = 12.0
)
)
val scope = rememberCoroutineScope()
Column(modifier = modifier.fillMaxSize()) {
// Botones
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
Button(onClick = {
scope.launch {
mapViewState.moveCameraTo(
MapCameraPosition(
position = marker1,
zoom = 15
),
durationMillis = 1000
)
}
}) {
Text("Tokyo Tower")
}
Button(onClick = {
scope.launch {
mapViewState.moveCameraTo(
MapCameraPosition(
position = marker2,
zoom = 15
),
durationMillis = 1000
)
}
}) {
Text("Sky Tree")
}
}
// 地図
GoogleMapView(
modifier = Modifier.fillMaxSize(),
state = mapViewState
) {
Marker(position = marker1, icon = ColorDefaultIcon(label = "TT"))
Marker(position = marker2, icon = ColorDefaultIcon(label = "ST"))
}
}
}

6-2. Monitorear eventos de movimiento de cámara

Escucha eventos de movimiento de cámara:

GoogleMapView(
modifier = modifier.fillMaxSize(),
state = mapViewState,
onCameraMoveStart = {
println("Movimiento de cámara iniciado")
},
onCameraMove = { cameraPosition ->
println("Posición de cámara: ${cameraPosition.position.latitude}, ${cameraPosition.position.longitude}")
},
onCameraMoveEnd = {
println("Movimiento de cámara finalizado")
}
) {
// Marcadores etc.
}

Paso 7: Cambiar entre SDKs de mapas

La ventaja más grande de MapConductor es la capacidad de cambiar proveedores de mapas con cambios mínimos de código.

Cambiar de Google Maps a Mapbox

import com.mapconductor.googlemaps.GoogleMapView
import com.mapconductor.googlemaps.rememberGoogleMapViewState
@Composable
fun MyMap() {
val mapViewState = rememberGoogleMapViewState(
cameraPosition = initialCamera
)
GoogleMapView(
state = mapViewState
) {
// Marcadores y otros componentes
}
}

¡Los marcadores, círculos, polilíneas y otros componentes funcionan con exactamente el mismo código!

Tabla de referencia de SDKs de mapas

SDK de mapasMapViewStateInterfaceMapView
Google MapsrememberGoogleMapViewStateGoogleMapView
MapboxrememberMapboxViewStateMapboxMapView
HERE MapsrememberHereMapViewStateHereMapView
ArcGISrememberArcGISMapViewStateArcGISMapView
MapLibrerememberMapLibreViewStateMapLibreMapView

Código de ejemplo completo

Aquí está el código de ejemplo completo que combina todo lo que has aprendido:

import androidx.compose.foundation.layout.*
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import com.mapconductor.core.*
import com.mapconductor.googlemaps.GoogleMapView
import com.mapconductor.googlemaps.rememberGoogleMapViewState
import kotlinx.coroutines.launch
@Composable
fun CompleteSample(modifier: Modifier = Modifier) {
val context = LocalContext.current
// Información de posición
val marker1 = GeoPoint.fromLatLong(35.6586, 139.7454)
val marker2 = GeoPoint.fromLatLong(35.7101, 139.8107)
// Guardar posición tocada
var clickedPosition by remember { mutableStateOf<GeoPointInterface?>(null) }
val initialCamera = MapCameraPosition(
position = GeoPoint.fromLatLong(35.6812, 139.7671),
zoom = 12.0
)
val mapViewState = rememberGoogleMapViewState(
cameraPosition = initialCamera
)
val scope = rememberCoroutineScope()
val onMarkerClick: (MarkerState) -> Unit = { markerState ->
Toast
.makeText(
context,
"clicked: ${markerState.extra}",
Toast.LENGTH_SHORT,
)
.show()
}
Column(modifier = modifier.fillMaxSize()) {
// Botones de control
Row(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp),
horizontalArrangement = Arrangement.SpaceEvenly
) {
Button(onClick = {
scope.launch {
mapViewState.moveCameraTo(
MapCameraPosition(position = marker1, zoom = 15.0),
durationMillis = 1000
)
}
}) {
Text("TT")
}
Button(onClick = {
scope.launch {
mapViewState.moveCameraTo(
MapCameraPosition(position = marker2, zoom = 15.0),
durationMillis = 1000
)
}
}) {
Text("ST")
}
}
// Mapa
GoogleMapView(
modifier = Modifier.fillMaxSize(),
state = mapViewState,
onMapClick = { geoPoint ->
clickedPosition = geoPoint
}
) {
// Marcadores
Marker(
position = marker1,
icon = ColorDefaultIcon(
label = "TT",
fillColor = Color.Red,
),
extra = "marker1",
onClick = onMarkerClick
)
Marker(
position = marker2,
icon = ColorDefaultIcon(
label = "ST",
fillColor = Color.Blue
),
extra = "marker2",
onClick = onMarkerClick
)
// Marcador para posición tocada
clickedPosition?.let { position ->
Marker(
position = position,
icon = ColorDefaultIcon(
label = "!",
fillColor = Color.Green
),
extra = "clicked",
onClick = onMarkerClick
)
}
// Círculo
Circle(
center = marker1,
radiusMeters = 1000,
strokeColor = Color.Red,
fillColor = Color.Red.copy(alpha = 0.2f)
)
Circle(
center = marker2,
radiusMeters = 1000,
strokeColor = Color.Blue,
fillColor = Color.Blue.copy(alpha = 0.2f)
)
// Polilínea
Polyline(
points = listOf(marker1, marker2),
strokeColor = Color.Magenta,
strokeWidth = 3.dp
)
}
}
}

Próximos pasos

Has aprendido los conceptos básicos del SDK de MapConductor. Para aprender más, consulta:

Solución de problemas

Mapa no se muestra

  • Verifica que tu clave API esté configurada correctamente
  • Comprueba tu conexión a Internet
  • Verifica que los permisos requeridos estén añadidos en AndroidManifest.xml

Errores de compilación

  • Verifica que minSdk esté configurado en 26 o superior
  • Comprueba que las versiones de Kotlin y Compose son compatibles
  • Verifica que las dependencias se hayan añadido correctamente

Los marcadores no son clicables

  • Verifica que MarkerState.onClick esté configurado
  • Asegúrate de que los marcadores tengan la propiedad extra configurada