Following several tutorials on the internet, I have managed to paint a Google map in my application:
@Composable
fun MyMap(
lat: Double,
lon: Double
) {
val mapView = rememberMapViewWithLifeCycle()
Column(
modifier = Modifier
.background(Color.White)
) {
AndroidView(
{ mapView }
) { mapView ->
CoroutineScope(Dispatchers.Main).launch {
val map = mapView.awaitMap()
map.uiSettings.isZoomControlsEnabled = false
val destination = LatLng(lat, lon)
map.moveCamera(CameraUpdateFactory.newLatLngZoom(destination, 16f))
val markerOptionsDestination = MarkerOptions()
.position(destination)
map.addMarker(markerOptionsDestination)
map.mapType = com.google.android.libraries.maps.GoogleMap.MAP_TYPE_HYBRID
}
}
}
}
@Composable
fun rememberMapViewWithLifeCycle(): MapView {
val context = LocalContext.current
val mapView = remember {
MapView(context).apply {
id = R.id.map_frame
}
}
val lifeCycleObserver = rememberMapLifecycleObserver(mapView)
val lifeCycle = LocalLifecycleOwner.current.lifecycle
DisposableEffect(lifeCycle) {
lifeCycle.addObserver(lifeCycleObserver)
onDispose {
lifeCycle.removeObserver(lifeCycleObserver)
}
}
return mapView
}
@Composable
fun rememberMapLifecycleObserver(mapView: MapView): LifecycleEventObserver =
remember(mapView) {
LifecycleEventObserver { _, event ->
when (event) {
Lifecycle.Event.ON_CREATE -> mapView.onCreate(Bundle())
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 -> throw IllegalStateException()
}
}
}
I load this composable from another composable where I have more elements, like texts and so on:
@Composable
fun MyMain() {
Box(
modifier = Modifier
.fillMaxWidth()
.size(300.dp)
) {
MyMap(lat, lon)
}
}
The map takes time to load, not long, maybe 1 second or less. But I would like the MyMain composable instead of being empty box (the box that contains the map) that second, to show a loading spinner. How could I implement this?
CodePudding user response:
You can probably do something like this:
If the map isn't actually fully loaded after mapView.awaitMap() try replacing the line with a delay(1000). (or longer than 1000 ms)
@Composable
fun MyMap(
lat: Double,
lon: Double,
) {
val mapView = rememberMapViewWithLifeCycle()
var isMapLoading by remember { mutableStateOf(true) }
LaunchedEffect(mapView) {
mapView.awaitMap()
isMapLoading = false
}
Box {
AndroidView(
{ mapView }
) { mapView ->
CoroutineScope(Dispatchers.Main).launch {
val map = mapView.awaitMap()
map.uiSettings.isZoomControlsEnabled = false
val destination = LatLng(lat, lon)
map.moveCamera(CameraUpdateFactory.newLatLngZoom(destination, 16f))
val markerOptionsDestination = MarkerOptions()
.position(destination)
map.addMarker(markerOptionsDestination)
map.mapType = com.google.android.libraries.maps.GoogleMap.MAP_TYPE_HYBRID
}
}
if (isMapLoading) {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.matchParentSize()
.background(Color.White)
) {
CircularProgressIndicator()
}
}
}
}
