adek
adek

Reputation: 3121

Get zoom level without getting recomposition for the whole GoogleMap

I'm using Google Maps with Compose. I've got one problem to solve. I thought it will be quite easy to code but it looks like I'm missing something.

My Google Map in compose is quite common:

GoogleMap(
    modifier = Modifier.fillMaxSize(),
    cameraPositionState = cameraPositionState,
    properties = MapProperties(isMyLocationEnabled = true),
    uiSettings = MapUiSettings(
        myLocationButtonEnabled = false,
        zoomControlsEnabled = false,
        zoomGesturesEnabled = true,
        mapToolbarEnabled = true
    )
)

I want to skip recomposition when zoom level will reach let's say level 14. I want to change markers. I've got already markers. The whole list.

The problem is - every time I'm reading cameraPositionState value - the whole GoogleMap is getting recomposed (also markers).

I was able to limit number or recomposition by using this approach:

LaunchedEffect(localCameraPositionState.isMoving && cameraPositionState.cameraMoveStartedReason==CameraMoveStartedReason.GESTURE) {
...
}

But it's not the solution. The issue is - every time I'm trying to read cameraPositionState.position.zoom - it gets refreshed.

I want to push some event to markers when the zoom will reach 14 level.

What's the best approach to do that?

Upvotes: 2

Views: 1736

Answers (2)

Austin Duran
Austin Duran

Reputation: 103

I was having a similar issue. I only wanted to recompose at a certain zoom for my markers. So I did something like this:

    val zoomLevel = remember { mutableStateOf(0f) }

    LaunchedEffect(Unit) {
        snapshotFlow { cameraPositionState.position.zoom }
            .collect { zoom ->
                if (zoom > 12.715378f) {
                    zoomLevel.value = zoom
                }
            }
    }

Upvotes: 2

Phil Dukhov
Phil Dukhov

Reputation: 87804

If you wanna change your view on some state change, you can use derivedStateOf:

val isMoving by remember { derivedStateOf { cameraPositionState.isMoving } }

Now if you need isMoving in your view tree, recomposition will only happen when cameraPositionState.isMoving is changed, not when any of cameraPositionState variables changes - as long as you don't use cameraPositionState in other places.


In case you need to trigger some action, and don't need to recompose at all, you can use snapshotFlow:

LaunchedEffect(Unit) {
    snapshotFlow { cameraPositionState.isMoving }
        .collect { isMoving ->
            someAction(isMoving)
        }
}

Basically both derivedStateOf and snapshotFlow works the same: you can calculate result value depending on any number of states, and only if result calculation is different since the last calculation, state is gonna be updated or flow value is gonna be emitted.

Upvotes: 1

Related Questions