From 8abd5219aa7407e3ce9530a46061212ffd415f33 Mon Sep 17 00:00:00 2001 From: Johan von Forstner Date: Sat, 27 Jun 2020 18:45:33 +0200 Subject: [PATCH] improvements to marker animations --- .../vonforst/evmap/fragment/MapFragment.kt | 63 ++++++++++--------- .../java/net/vonforst/evmap/ui/MarkerUtils.kt | 50 +++++++-------- 2 files changed, 56 insertions(+), 57 deletions(-) diff --git a/app/src/main/java/net/vonforst/evmap/fragment/MapFragment.kt b/app/src/main/java/net/vonforst/evmap/fragment/MapFragment.kt index 1e5140af..f4dc8498 100644 --- a/app/src/main/java/net/vonforst/evmap/fragment/MapFragment.kt +++ b/app/src/main/java/net/vonforst/evmap/fragment/MapFragment.kt @@ -91,6 +91,7 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac private var clusterMarkers: List = emptyList() private var searchResultMarker: Marker? = null private var connectionErrorSnackbar: Snackbar? = null + private var previousChargepointIds: Set? = null private lateinit var clusterIconGenerator: ClusterIconGenerator private lateinit var chargerIconGenerator: ChargerIconGenerator @@ -643,39 +644,41 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac val chargers = chargepoints.filterIsInstance() val chargepointIds = chargers.map { it.id }.toSet() - // remove markers that disappeared - markers.entries.toList().forEach { - if (!chargepointIds.contains(it.value.id)) { - if (it.key.isVisible) { - val tint = getMarkerTint(it.value) - val highlight = it.value == vm.chargerSparse.value - val fault = it.value.faultReport != null - animator.animateMarkerDisappear(it.key, tint, highlight, fault) - } else { - it.key.remove() + + if (chargers != markers.values) { + // remove markers that disappeared + val bounds = map.projection.visibleRegion.latLngBounds + markers.entries.toList().forEach { + if (!chargepointIds.contains(it.value.id)) { + // animate marker if it is visible, otherwise remove immediately + if (bounds.contains(it.key.position)) { + val tint = getMarkerTint(it.value) + val highlight = it.value == vm.chargerSparse.value + val fault = it.value.faultReport != null + animator.animateMarkerDisappear(it.key, tint, highlight, fault) + } else { + it.key.remove() + } + markers.remove(it.key) } - markers.remove(it.key) } - } - // add new markers - chargers.filter { - !markers.containsValue(it) - }.forEach { charger -> - val tint = getMarkerTint(charger) - val highlight = charger == vm.chargerSparse.value - val fault = charger.faultReport != null - val marker = map.addMarker( - MarkerOptions() - .position(LatLng(charger.coordinates.lat, charger.coordinates.lng)) - .icon( - chargerIconGenerator.getBitmapDescriptor( - tint, highlight = highlight, - fault = charger.faultReport != null - ) + // add new markers + val map1 = markers.values.map { it.id } + chargers.forEach { charger -> + if (!map1.contains(charger.id)) { + val tint = getMarkerTint(charger) + val highlight = charger == vm.chargerSparse.value + val fault = charger.faultReport != null + val marker = map.addMarker( + MarkerOptions() + .position(LatLng(charger.coordinates.lat, charger.coordinates.lng)) + .visible(false) ) - ) - animator.animateMarkerAppear(marker, tint, highlight, fault) - markers[marker] = charger + animator.animateMarkerAppear(marker, tint, highlight, fault) + markers[marker] = charger + } + } + previousChargepointIds = chargepointIds } clusterMarkers = clusters.map { cluster -> map.addMarker( diff --git a/app/src/main/java/net/vonforst/evmap/ui/MarkerUtils.kt b/app/src/main/java/net/vonforst/evmap/ui/MarkerUtils.kt index 26a37251..2d5af6ce 100644 --- a/app/src/main/java/net/vonforst/evmap/ui/MarkerUtils.kt +++ b/app/src/main/java/net/vonforst/evmap/ui/MarkerUtils.kt @@ -19,7 +19,7 @@ fun getMarkerTint(charger: ChargeLocation): Int = when { } class MarkerAnimator(val gen: ChargerIconGenerator) { - val animatingMarkers = hashMapOf() + private val animatingMarkers = hashMapOf() fun animateMarkerAppear( marker: Marker, @@ -27,18 +27,13 @@ class MarkerAnimator(val gen: ChargerIconGenerator) { highlight: Boolean, fault: Boolean ) { - animatingMarkers[marker]?.cancel() - animatingMarkers.remove(marker) + animatingMarkers[marker.id]?.cancel() + animatingMarkers.remove(marker.id) val anim = ValueAnimator.ofInt(0, 20).apply { duration = 250 interpolator = LinearOutSlowInInterpolator() addUpdateListener { animationState -> - if (!marker.isVisible) { - cancel() - animatingMarkers.remove(marker) - return@addUpdateListener - } val scale = animationState.animatedValue as Int marker.setIcon( gen.getBitmapDescriptor( @@ -48,12 +43,15 @@ class MarkerAnimator(val gen: ChargerIconGenerator) { fault = fault ) ) + marker.isVisible = true } addListener(onEnd = { - animatingMarkers.remove(marker) + animatingMarkers.remove(marker.id) + }, onCancel = { + animatingMarkers.remove(marker.id) }) } - animatingMarkers[marker] = anim + animatingMarkers[marker.id] = anim anim.start() } @@ -63,18 +61,13 @@ class MarkerAnimator(val gen: ChargerIconGenerator) { highlight: Boolean, fault: Boolean ) { - animatingMarkers[marker]?.cancel() - animatingMarkers.remove(marker) + animatingMarkers[marker.id]?.cancel() + animatingMarkers.remove(marker.id) val anim = ValueAnimator.ofInt(20, 0).apply { duration = 200 interpolator = FastOutLinearInInterpolator() addUpdateListener { animationState -> - if (!marker.isVisible) { - cancel() - animatingMarkers.remove(marker) - return@addUpdateListener - } val scale = animationState.animatedValue as Int marker.setIcon( gen.getBitmapDescriptor( @@ -86,32 +79,35 @@ class MarkerAnimator(val gen: ChargerIconGenerator) { ) } addListener(onEnd = { - animatingMarkers.remove(marker) marker.remove() + animatingMarkers.remove(marker.id) + }, onCancel = { + marker.remove() + animatingMarkers.remove(marker.id) }) } - animatingMarkers[marker] = anim + animatingMarkers[marker.id] = anim anim.start() } fun animateMarkerBounce(marker: Marker) { - animatingMarkers[marker]?.cancel() - animatingMarkers.remove(marker) + animatingMarkers[marker.id]?.cancel() + animatingMarkers.remove(marker.id) val anim = ValueAnimator.ofFloat(0f, 1f).apply { duration = 700 interpolator = BounceInterpolator() addUpdateListener { state -> - if (!marker.isVisible) { - cancel() - animatingMarkers.remove(marker) - return@addUpdateListener - } val t = max(1f - state.animatedValue as Float, 0f) / 2 marker.setAnchor(0.5f, 1.0f + t) } + addListener(onEnd = { + animatingMarkers.remove(marker.id) + }, onCancel = { + animatingMarkers.remove(marker.id) + }) } - animatingMarkers[marker] = anim + animatingMarkers[marker.id] = anim anim.start() } } \ No newline at end of file