From 4f329f518656a0482ff0d7d40f4ae33187622808 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20Lo=CC=81pez=20Man=CC=83as?= Date: Mon, 4 Aug 2025 21:48:57 +0200 Subject: [PATCH 1/2] fix: wandering marker --- demo/src/main/res/layout/multi_profile.xml | 2 +- .../clustering/view/ClusterRendererMultipleItems.java | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/demo/src/main/res/layout/multi_profile.xml b/demo/src/main/res/layout/multi_profile.xml index bbd407769..0cec5a36e 100644 --- a/demo/src/main/res/layout/multi_profile.xml +++ b/demo/src/main/res/layout/multi_profile.xml @@ -22,7 +22,7 @@ new LinearInterpolator(); case EASE_IN, ACCELERATE -> new AccelerateInterpolator(); @@ -173,7 +174,7 @@ public void setAnimationInterpolator(TimeInterpolator interpolator) { public ClusterRendererMultipleItems(Context context, GoogleMap map, ClusterManager clusterManager) { mMap = map; mAnimate = true; - mAnimationDurationMs = 300; + mAnimationDurationMs = 5000; mDensity = context.getResources().getDisplayMetrics().density; mIconGenerator = new IconGenerator(context); mIconGenerator.setContentView(makeSquareTextView(context)); @@ -529,8 +530,7 @@ public void run() { final Point point = mSphericalMercatorProjection.toPoint(marker.position); final Point closest = findClosestCluster(newClustersOnScreen, point); if (closest != null) { - LatLng animateTo = mSphericalMercatorProjection.toLatLng(closest); - markerModifier.animateThenRemove(marker, marker.position, animateTo); + markerModifier.remove(true, marker.marker); RendererLogger.d("ClusterRenderer", "Animating then removing marker at position: " + marker.position); } else if (mClusterMarkerCache.mCache.keySet().iterator().hasNext() && mClusterMarkerCache.mCache.keySet().iterator().next().getItems().contains(marker.clusterItem)) { T foundItem = null; @@ -1153,7 +1153,7 @@ private void perform(MarkerModifier markerModifier) { if (animateFrom != null) { markerModifier.animate(markerWithPosition, animateFrom, item.getPosition()); RendererLogger.d("ClusterRenderer", "Animating marker from " + animateFrom + " to " + item.getPosition()); - } else if (currentLocation != null) { + } else { markerModifier.animate(markerWithPosition, currentLocation, item.getPosition()); RendererLogger.d("ClusterRenderer", "Animating marker from " + currentLocation + " to " + item.getPosition()); } From 076118a2685338775ed6fc6d55cba9f46aff1477 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20Lo=CC=81pez=20Man=CC=83as?= Date: Wed, 13 Aug 2025 09:53:16 +0200 Subject: [PATCH 2/2] fix: animating or removing marker depending on distance --- .../view/ClusterRendererMultipleItems.java | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/library/src/main/java/com/google/maps/android/clustering/view/ClusterRendererMultipleItems.java b/library/src/main/java/com/google/maps/android/clustering/view/ClusterRendererMultipleItems.java index 7922120dc..d3e3a8ed2 100644 --- a/library/src/main/java/com/google/maps/android/clustering/view/ClusterRendererMultipleItems.java +++ b/library/src/main/java/com/google/maps/android/clustering/view/ClusterRendererMultipleItems.java @@ -53,6 +53,7 @@ import com.google.android.gms.maps.model.MarkerOptions; import com.google.maps.android.R; import com.google.maps.android.RendererLogger; +import com.google.maps.android.SphericalUtil; import com.google.maps.android.clustering.Cluster; import com.google.maps.android.clustering.ClusterItem; import com.google.maps.android.clustering.ClusterManager; @@ -435,6 +436,8 @@ private class RenderTask implements Runnable { private SphericalMercatorProjection mSphericalMercatorProjection; private float mMapZoom; + private static final double EPSILON = 1e-9; + private RenderTask(Set> clusters) { this.clusters = clusters; } @@ -452,6 +455,10 @@ public void setMapZoom(float zoom) { this.mSphericalMercatorProjection = new SphericalMercatorProjection(256 * Math.pow(2, Math.min(zoom, mZoom))); } + private boolean areClose(double a, double b) { + return Math.abs(a - b) < EPSILON; + } + @SuppressLint("NewApi") @Override public void run() { @@ -530,9 +537,17 @@ public void run() { final Point point = mSphericalMercatorProjection.toPoint(marker.position); final Point closest = findClosestCluster(newClustersOnScreen, point); if (closest != null) { - markerModifier.remove(true, marker.marker); - RendererLogger.d("ClusterRenderer", "Animating then removing marker at position: " + marker.position); - } else if (mClusterMarkerCache.mCache.keySet().iterator().hasNext() && mClusterMarkerCache.mCache.keySet().iterator().next().getItems().contains(marker.clusterItem)) { + LatLng animateTo = mSphericalMercatorProjection.toLatLng(closest); + if (areClose(marker.position.latitude, animateTo.latitude) && areClose(marker.position.longitude, animateTo.longitude)) { + // Treat them as the same, no need for animation + markerModifier.remove(true, marker.marker); + RendererLogger.d("ClusterRenderer", "Removing marker without animation (coordinates are very close)"); + } else { + // If they are not close, proceed with the original logic + markerModifier.animateThenRemove(marker, marker.position, animateTo); + } + } + else if (mClusterMarkerCache.mCache.keySet().iterator().hasNext() && mClusterMarkerCache.mCache.keySet().iterator().next().getItems().contains(marker.clusterItem)) { T foundItem = null; for (Cluster cluster : mClusterMarkerCache.mCache.keySet()) { for (T clusterItem : cluster.getItems()) {