Disable clustering at maximum zoom level with googles android-maps-utils

I am clustering markers on a Google map on Android using a cluster from android-maps-utils . I want to disable clustering when the map is at the maximum zoom level (i.e. Always display individual ClusterItems objects if the map is at the maximum zoom level, otherwise the cluster is as usual).

I can almost get it working by running a test for the zoom level in shouldRenderAsCluster () in a custom class extending DefaultClusterRenderer. However, my solution is one step behind the actual zoom level. For example, if the maximum zoom for the map is level 21, and the user zooms in from level 20 to level 21, then the check will include the current zoom level 20. If the user is scaled to level 20, the check will get level 21 ClusterItems gets rendered as separate elements as I want, but one zoom action is too late.

I get "Current Zoom" (which, apparently, is not current) from the mZoom variable, which is set to DefaultClusterRenderer.

This is the code:

public class UserClusterRenderer extends PosMapDefaultClusterRenderer<UserClusterItem> {

    // ...

    @Override
    protected boolean shouldRenderAsCluster(Cluster cluster) {
        return mZoom < mMap.getMaxZoomLevel() && cluster.getSize() > 1;
    }
}

mZoom mMap DefaultClusterRenderer. , DefaultClusterRenderer PosMapDefaultClusterRenderer. , mZoom mMap , UserClusterRenderer.

mZoom ? , ?

animateCamera . . .

StackOverflow, , .. .

: :

public class UserClusterRenderer extends DefaultClusterRenderer<UserClusterItem> {

    GoogleMap mMapCopy; // Store a ref to the map here from constructor

    // ...

    @Override
    protected boolean shouldRenderAsCluster(Cluster cluster) {
        float currentZoom = mMapCopy.getCameraPosition().zoom;
        float currentMaxZoom = mMapCopy.getMaxZoomLevel();
        return currentZoom < currentMaxZoom && cluster.getSize() > 1;
    }
}
+3
4

, mZoom. ( ), :

mMap.getCameraPosition().zoom

shouldRenderAsCluster() . , , . SO.

0

@Marc D , .

, , , GoogleMap.onCameraMoveListener, onCameraMoveListener .

:

public class MaxZoomClusterRenderer extends DefaultClusterRenderer<JobClusterItem> implements ClusterManager.OnClusterItemClickListener<JobClusterItem>, GoogleMap.OnCameraMoveListener {

    private final GoogleMap mMap;
    private float currentZoomLevel, maxZoomLevel;

    public MaxZoomClusterRenderer(Context context, GoogleMap map, ClusterManager<JobClusterItem> clusterManager, float currentZoomLevel, float maxZoomLevel) {
        super(context, map, clusterManager);

        this.mMap = map;
        this.currentZoomLevel = currentZoomLevel;
        this.maxZoomLevel = maxZoomLevel;
    }

    @Override
    public void onCameraMove() {
        currentZoomLevel = mMap.getCameraPosition().zoom;
    }

    @Override
    protected boolean shouldRenderAsCluster(Cluster<JobClusterItem> cluster) {
        // determine if superclass would cluster first, based on cluster size
        boolean superWouldCluster = super.shouldRenderAsCluster(cluster);

        // if it would, then determine if you still want it to based on zoom level
        if (superWouldCluster) {
            superWouldCluster = currentZoomLevel < maxZoomLevel;
        }

        return superWouldCluster;
    }
}

/ :

mClusterManager = new ClusterManager<>(getContext(), _map);

// Set custom renderer to allow us to control appearance and behaviour of the clustering
MaxZoomClusterRenderer customRenderer = new MaxZoomClusterRenderer(getContext(), _map, mClusterManager, _map.getCameraPosition().zoom, 18.0f);
mClusterManager.setRenderer(customRenderer);
_map.setOnCameraMoveListener(customRenderer);
_map.setOnCameraIdleListener(mClusterManager);
_map.setOnMarkerClickListener(mClusterManager);

JobClusterItem - , ClusterItem.

, shouldRenderAsCluster.

+4

Thank you Brino for pointing me in the right direction. I would suggest making an onCameraIdleListener listener, since onCameraMoved is often called sooooo. I already used the onCameraIdle function for the map, so I did something similar and used the Breenos answer to update the current zoom level inside the renderer by simply disabling onCameraMoved using onCameraIdle.

private ClusterManager<ClusterItems> mClusterManager;
private ClusterRenderer mRenderer;
private GoogleMap mMap;

@Override
public void onMapReady(GoogleMap googleMap) {
    Log.v("------Map Ready--","-----yuppers");
    mMap = googleMap;
    mMap.setOnCameraIdleListener(this);
    mClusterManager = new ClusterManager<>(this, mMap);
    mRenderer = new ClusterRenderer(getContext(), mMap, mMap.getCameraPosition().zoom);
    mClusterManager.setRenderer(mRenderer);
//        mMap.setOnCameraMoveListener(mRenderer);
//        mMap.setOnCameraIdleListener(mClusterManager);
    mMap.setOnMarkerClickListener(mClusterManager);
    mMap.setOnInfoWindowClickListener(mClusterManager);
    mClusterManager.setOnClusterClickListener(this);
    mClusterManager.setOnClusterInfoWindowClickListener(this);
    mClusterManager.setOnClusterItemClickListener(this);
    mClusterManager.setOnClusterItemInfoWindowClickListener(this); 

}   
@Override
public void onCameraIdle() {
    mClusterManager.onCameraIdle();
    mRenderer.onCameraIdle();
}
0
source

Try it:

@Override
protected boolean shouldRenderAsCluster(Cluster cluster) {
    Float zoom = null;
    try {
        this.getClass().getSuperclass().getSuperclass().getDeclaredField("mZoom").setAccessible(true);
        Field field = this.getClass().getSuperclass().getSuperclass().getDeclaredField("mZoom");
        field.setAccessible(true);
        zoom = (Float) field.get(this);
        } catch (NoSuchFieldException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        return cluster.getSize() >= MINIMUM_NUMBER_OF_MARKERS_IN_CLUSTER;
    }
    return cluster.getSize() >= MINIMUM_NUMBER_OF_MARKERS_IN_CLUSTER && (zoom != null ? zoom < MAX_CLUSTERING_ZOOM_LEVEL : true);
}

Decision through reflection

0
source

Source: https://habr.com/ru/post/1648120/


All Articles