googlemaps / googlemaps/android-maps-compose
Cancelled animation corrupts CameraPositionState and prevents drag gesture
- Dominant language
- Kotlin
- Stars
- 1.3k
- Forks
- 181
- Avg merge
- 2d 23h
- Merged PRs (30d)
- 18
Description
android-maps-compose 4.3.0
When an animation occurs and is cancelled (and in other circumstances that I did not manage to reproduce), the CameraPositionState gets corrupted and a drag gesture on the map doesn't work anymore as intended. Here is a code to reproduce the bug (click several times on the button and try to move the map, zoom is not affected somehow).
#### Environment details
1. android-maps-compose 4.3.0
2. doesn't seem to occur on the simulator, please use a real device.
#### Steps to reproduce
1. Click several times on the button that animates the card, causing cancellation exceptions (caught and displayed)
2. Try to move the map, it doesn't move as intended (zoom is not affected somehow)
#### Code example
```
class RecompositionActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val cameraPositionState = rememberCameraPositionState {
position = defaultCameraPosition
}
Box(Modifier.fillMaxSize()) {
MapsComposeSampleTheme {
GoogleMapView(
modifier = Modifier.matchParentSize(),
cameraPositionState = cameraPositionState
)
}
}
}
}
@Composable
fun GoogleMapView(
modifier: Modifier = Modifier,
cameraPositionState: CameraPositionState = rememberCameraPositionState(),
content: @Composable () -> Unit = {},
) {
var location by remember { mutableStateOf(singapore) }
var zoom by remember { mutableStateOf(5f) }
val context = LocalContext.current
val singaporeState = MarkerState(position = location)
val mapProperties = remember {
MapProperties(
isBuildingEnabled = false,
isIndoorEnabled = false,
isMyLocationEnabled = false,
isTrafficEnabled = false,
mapType = MapType.SATELLITE,
)
}
val mapOptions = remember {
GoogleMapOptions()
.ambientEnabled(false)
.mapToolbarEnabled(false)
.compassEnabled(false)
}
val uiSettings = remember {
MapUiSettings(
compassEnabled = false,
indoorLevelPickerEnabled = false,
mapToolbarEnabled = false,
myLocationButtonEnabled = false,
rotationGesturesEnabled = false,
scrollGesturesEnabledDuringRotateOrZoom = false,
tiltGesturesEnabled = false,
zoomControlsEnabled = false,
)
}
val mapVisible by remember { mutableStateOf(true) }
if (mapVisible) {
LaunchedEffect(zoom) {
try {
cameraPositionState.animate(
update = CameraUpdateFactory.newCameraPosition(
CameraPosition(
cameraPositionState.position.target,
zoom,
0f,
0f
),
), durationMs = 1000
)
} catch(e: CancellationException) {
Toast.makeText(context, e.message, Toast.LENGTH_SHORT).show()
} catch(e: Exception) {
Toast.makeText(context, e.message, Toast.LENGTH_SHORT).show()
}
}
// Detect when the map starts moving and print the reason
LaunchedEffect(cameraPositionState.isMoving) {
if (cameraPositionState.isMoving) {
Log.d(TAG, "Map camera started moving due to ${cameraPositionState.cameraMoveStartedReason.name}")
}
}
GoogleMap(
modifier = modifier.fillMaxSize(),
cameraPositionState = cameraPositionState,
googleMapOptionsFactory = {mapOptions},
onMapLoaded = {},
properties = mapProperties,
uiSettings = uiSettings,
onPOIClick = {
Log.d(TAG, "POI clicked: ${it.name}")
}
) {
val markerClick: (Marker) -> Boolean = {
Log.d(TAG, "${it.title} was clicked")
cameraPositionState.projection?.let { projection ->
Log.d(TAG, "The current projection is: $projection")
}
false
}
Marker(
state = singaporeState,
title = "Marker in Singapore",
onClick = markerClick
)
content()
}
Column {
Button(onClick = {
val randomValue = Random.nextInt(3)
location = when (randomValue) {
0 -> singapore
1 -> singapore2
2 -> singapore3
else -> singapore
}
zoom = when (randomValue) {
0 -> 3f
1 -> 6f
2 -> 15f
else -> 16f
}
}) {
Text("Change Location & Zoom")
}
}
}
}
}
```
Thanks by advance!
Contributor guide
Assessment
This issue has not been assessed yet.