mapbox-maps-android
mapbox-maps-android copied to clipboard
Icon blinks zooming in/out with PointAnnotationGroup/Compose
Environment
- Android OS version: 14
- Devices affected: Not device specific but is seen on Samsung s21 ultra as well as Google Pixel 6.
- Maps SDK Version: Can be observed from 10.x all the way to 11.2.2 (can not verify on 11.3 at this point)
- Compose version: 1.6.2
Observed behavior and steps to reproduce
Icon blinks when zoom in/out. The blinking intensifies when zooming out and the icons are getting closer to each other. Blinking appears much less often when there are few than 3 icons visible within the map region (but it does still happen sometimes).
Please see video capture here: https://youtube.com/shorts/es0iWngndEo?feature=share
Expected behavior
Icon(s) do not blink, or only blink when clustering ops are happening. Blinking should not happen during typical zoom in/out operation when zoom level is large enough that clustering is not a factor.
Notes / preliminary analysis
MapboxMap(
modifier = Modifier.fillMaxSize(),
mapViewportState = mapViewportState,
mapInitOptionsFactory = { context ->
MapInitOptions(
context = context,
styleUri = "mapbox://styles/moonmapper/cloxllb7700q601qj462k2q76",
)
},
gesturesSettings = GesturesSettings {
quickZoomEnabled = true
doubleTapToZoomInEnabled = true
pitchEnabled = false
this.build()
},
onMapClickListener = { point ->
....
}
) {
MapEffect(mapViewportState.cameraState.center) { mapView ->
mapView.location.updateSettings {
enabled = true
}
val mapboxMap = mapView.mapboxMap
mapView.scalebar.enabled = false
.....
}
...
PointAnnotationGroup(
iconOptional = true,
iconAllowOverlap = true,
iconIgnorePlacement = true,
iconPitchAlignment = IconPitchAlignment.MAP,
annotations = listOf(
flightWithPositions.toFlightAnnotationOptions(),
vehicleWithPositions.toVehicleAnnotationOptions(),
userWithPositions.toUserAnnotationOptions()
).flatten()
.filter {
it.getPoint()?.let { point ->
ComposeMapboxManager.bounds.value?.contains(point, true) == true
} ?: false },
annotationConfig = AnnotationConfig(
annotationSourceOptions = AnnotationSourceOptions(
clusterOptions = ClusterOptions(
clusterMaxZoom = 16,
textColor = Color(0xFF000000).toArgb(),
textSize = 12.0,
circleRadiusExpression = literal(15.0),
colorLevels = listOf(
Pair(100, Color.Red.toArgb()),
Pair(50, Color.Blue.toArgb()),
Pair(0, Color(0xFFB0B7C3).toArgb())
)
)
)
),
onClick = { annotation ->
....
}
)
}
Here is how I typically handle the creation of PointAnnotationOptions
@Composable
fun List<VehicleWithPosition>.toVehicleAnnotationOptions(): List<PointAnnotationOptions> {
return this.map { vehicle ->
val vehiclePoint = Point.fromLngLat(
vehicle.positions[0].longitude,
vehicle.positions[0].latitude
)
var options by remember {
mutableStateOf(
PointAnnotationOptions()
.withPoint(vehiclePoint)
.withData(
gson.toJsonTree(
AnnotationItem(
vehicleLasId = vehicle.vehicle.lasId
), AnnotationItem::class.java
)
)
)
}
LaunchedEffect(
vehicle.positions[0].heading,
vehicle.positions[0].latitude,
vehicle.positions[0].longitude,
vehicle.vehicle.getGseStatus(),
vehicle.matchSelectedVehicle(),
if (!ComposeMapboxManager.mapMoving.value) ComposeMapboxManager.cameraOptions.value?.bearing else null
) {
val selected = vehicle.matchSelectedVehicle()
val relativeHeading = vehicle.positions[0].heading - (ComposeMapboxManager.cameraOptions.value?.bearing?.toInt() ?: 0)
val key = VehicleKey(
vehicle.vehicle.name,
vehicle.vehicle.getGseStatus(),
relativeHeading,
selected
)
withContext(Dispatchers.IO) {
val iconImage = if (vehicleIconMap.get(key) == null) {
vehicleMarkerView(
heading = relativeHeading,
name = vehicle.vehicle.name,
type = vehicle.vehicle.type,
status = vehicle.vehicle.getGseStatus(),
batteryLevel = vehicle.positions[0].battery,
selected = selected
).also {
vehicleIconMap.put(key, it)
}
} else {
vehicleIconMap[key]!!
}
val updatedVehicleMarker = PointAnnotationOptions()
.withData(
gson.toJsonTree(
AnnotationItem(
vehicleLasId = vehicle.vehicle.lasId
), AnnotationItem::class.java
)
)
.withIconImage(iconImage)
.withPoint(vehiclePoint)
options = updatedVehicleMarker
}
}
options.symbolSortKey = 3.0
options.iconAnchor = IconAnchor.CENTER
options
}
}`