Map styles
Contents
The Mobile Maps SDK examples require that you first complete the initial project setup.
This example provides a reference of how to change map styles in a Jetpack Compose environment. It allows switching between different map styles using buttons, similar to the Map Styles code example for Java and Kotlin.
import android.content.Context
import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.compose.LocalLifecycleOwner
import com.trimblemaps.account.LicensedFeature
import com.trimblemaps.account.TrimbleMapsAccountManager
import com.trimblemaps.account.models.TrimbleMapsAccount
import com.trimblemaps.mapsdk.TrimbleMaps
import com.trimblemaps.mapsdk.camera.CameraPosition
import com.trimblemaps.mapsdk.geometry.LatLng
import com.trimblemaps.mapsdk.maps.MapView
import com.trimblemaps.mapsdk.maps.OnMapReadyCallback
import com.trimblemaps.mapsdk.maps.Style
import com.trimblemaps.mapsdk.maps.TrimbleMapsMap
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
// IMPORTANT: Use your real API key
MapStylesScreen(apiKey = "YOUR-API-KEY")
}
}
}
@Composable
fun MapStylesScreen(apiKey: String) {
val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current
// Gate rendering the MapView until account initialization completes
var isInitialized by remember { mutableStateOf(false) }
var trimbleMap by remember { mutableStateOf<TrimbleMapsMap?>(null) }
var chosenStyle by remember { mutableStateOf("Mobile_Day Style") }
// Initialize the Trimble account/session once.
LaunchedEffect(apiKey) {
// Build account with your API key and the Maps SDK licensed feature
val account = TrimbleMapsAccount.builder()
.apiKey(apiKey)
.addLicensedFeature(LicensedFeature.MAPS_SDK)
.build()
// Initialize and block until ready
TrimbleMapsAccountManager.initialize(account)
TrimbleMapsAccountManager.awaitInitialization()
// Obtain the Trimble Maps instance BEFORE creating/using MapView
TrimbleMaps.getInstance(context)
isInitialized = true
}
if (isInitialized) {
val mapView = rememberMapViewWithLifecycle(context, lifecycleOwner.lifecycle)
Box(modifier = Modifier.fillMaxSize()) {
AndroidView(
modifier = Modifier.fillMaxSize(),
factory = { mapView },
update = { view ->
// Request a TrimbleMapsMap asynchronously
view.getMapAsync(OnMapReadyCallback { map ->
trimbleMap = map
// Set the initial camera position
val position = CameraPosition.Builder()
.target(LatLng(40.7584766, -73.9840227))
.zoom(13.0)
.build()
map.cameraPosition = position
// Set the initial style
map.setStyle(Style.TrimbleMobileStyle.MOBILE_DAY) {
chosenStyle = "Mobile_Day Style"
Toast.makeText(context, chosenStyle, Toast.LENGTH_SHORT).show()
}
})
}
)
// Style selection buttons
Column(
modifier = Modifier
.align(Alignment.BottomEnd)
.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
StyleButton("Mobile_Day", Style.TrimbleMobileStyle.MOBILE_DAY, "Mobile_Day Style") {
chosenStyle = it
trimbleMap?.setStyle(Style.TrimbleMobileStyle.MOBILE_DAY) {
Toast.makeText(context, chosenStyle, Toast.LENGTH_SHORT).show()
}
}
StyleButton("Mobile_Night", Style.TrimbleMobileStyle.MOBILE_NIGHT, "Mobile_Night Style") {
chosenStyle = it
trimbleMap?.setStyle(Style.TrimbleMobileStyle.MOBILE_NIGHT) {
Toast.makeText(context, chosenStyle, Toast.LENGTH_SHORT).show()
}
}
StyleButton("Mobile_Satellite", Style.TrimbleMobileStyle.MOBILE_SATELLITE, "Mobile_Satellite Style") {
chosenStyle = it
trimbleMap?.setStyle(Style.TrimbleMobileStyle.MOBILE_SATELLITE) {
Toast.makeText(context, chosenStyle, Toast.LENGTH_SHORT).show()
}
}
}
}
}
}
@Composable
private fun StyleButton(
text: String,
style: String,
styleName: String,
onStyleChange: (String) -> Unit
) {
Button(
onClick = { onStyleChange(styleName) },
modifier = Modifier.padding(vertical = 2.dp)
) {
Text(text)
}
}
/**
* Handle the lifecycle events from the map view, onDestroy etc.
*/
@Composable
private fun rememberMapViewWithLifecycle(
context: Context,
lifecycle: Lifecycle
): MapView {
// Create once per composition
val mapView = remember {
MapView(context)
}
// Hook the MapView into the lifecycle
DisposableEffect(lifecycle, mapView) {
val observer = LifecycleEventObserver { _, event ->
when (event) {
Lifecycle.Event.ON_CREATE -> { /* no-op (Trimble handled) */ }
Lifecycle.Event.ON_START -> mapView.onStart()
Lifecycle.Event.ON_RESUME -> mapView.onResume()
Lifecycle.Event.ON_PAUSE -> mapView.onPause()
Lifecycle.Event.ON_STOP -> mapView.onStop()
Lifecycle.Event.ON_DESTROY -> mapView.onDestroy()
else -> Unit
}
}
lifecycle.addObserver(observer)
onDispose {
lifecycle.removeObserver(observer)
try {
mapView.onDestroy()
} catch (_: Throwable) {
}
}
}
return mapView
}