简体   繁体   English

使用Googles android-maps-utils以最大缩放级别禁用群集

[英]Disable clustering at max zoom level with Googles android-maps-utils

I'm clustering markers on a Google map in Android using the clustering from android-maps-utils . 我使用android-maps-utils中的聚类在Android上的Google地图上聚类标记。 I want to disable the clustering when the map is at it's max zoom level (ie always render individual ClusterItems if the map is at max zoom level, otherwise cluster as normal). 我希望在地图处于最大缩放级别时禁用聚类(即,如果地图处于最大缩放级别,则始终渲染单个ClusterItems,否则聚类为正常)。

I'm able to almost get it working by doing a test for zoom level in shouldRenderAsCluster() in a custom class extending DefaultClusterRenderer. 通过在扩展DefaultClusterRenderer的自定义类中对shouldRenderAsCluster()进行缩放级别测试,我几乎可以使它工作。 However my solution lags one step behind the actual zoom level. 但是我的解决方案落后于实际缩放级别一步。 For instance if the max zoom for the map is level 21, and the user zooms in from level 20 to level 21, the check in shouldRenderAsCluster will get a current zoom level of 20. If the user then zooms out to level 20 the check will get level 21. The ClusterItems gets rendered as individual items like I want, but one zoom action too late. 例如,如果地图的最大缩放是21级,并且用户从级别20放大到级别21,则登记的应该是当前的缩放级别为20的当前缩放级别。如果用户然后缩小到级别20,则检查将得到级别21. ClusterItems被渲染为我想要的单个项目,但是一个缩放操作太迟了。

I get the "Current Zoom" (which is not really current apparently) from the variable mZoom that is set in DefaultClusterRenderer. 我从DefaultClusterRenderer中设置的变量mZoom中获得“当前缩放”(显然不是当前的)。

This is the code: 这是代码:

public class UserClusterRenderer extends PosMapDefaultClusterRenderer<UserClusterItem> {

    // ...

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

The variables mZoom and mMap are set in DefaultClusterRenderer. 变量mZoom和mMap在DefaultClusterRenderer中设置。 Because they have private access there I've made a copy of DefaultClusterRenderer called PosMapDefaultClusterRenderer. 因为他们有私人访问权限,所以我制作了一份名为PosMapDefaultClusterRenderer的DefaultClusterRenderer副本。 The only difference is that mZoom and mMap are declared protected instead so they're accessible in UserClusterRenderer. 唯一的区别是mZoom和mMap被声明为受保护,因此可以在UserClusterRenderer中访问它们。

Why is mZoom lagging one zoom action behind? 为什么mZoom落后于一个缩放动作? Is there a way to get the real zoom level for which the clusters are being rendered? 有没有办法获得正在渲染集群的真实缩放级别?

The zooming is done with a call to animateCamera using a cameraUpdate from a cameraPosition. 使用来自cameraPosition的cameraUpdate调用animateCamera完成缩放。

Also this is my first question on StackOverflow so any input on tags, formatting etc is welcome. 这也是我在StackOverflow上的第一个问题,所以欢迎任何关于标签,格式等的输入。

Edit: Working code after Vai's answer: 编辑:Vai回答后的工作代码:

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;
    }
}

@Marc DI was having the same issue with the thread exception, and the solution proposed above would not work for me. @Marc DI遇到与线程异常相同的问题,上面提出的解决方案对我不起作用。

To get around this, I passed in the initial zoom level and desired maximum zoom level for clustering to occur into the custom renderer as parameters, and then made the custom renderer class implement the GoogleMap.onCameraMoveListener so that it could pick up further changes to the zoom level, and set the onCameraMoveListener on the map to my instance of the custom renderer class. 为了解决这个问题,我将初始缩放级别和所需的最大缩放级别传递给自定义渲染器作为参数进行聚类,然后使自定义渲染器类实现GoogleMap.onCameraMoveListener,以便它可以进一步更改缩放级别,并将地图上的onCameraMoveListener设置为我的自定义渲染器类的实例。

The below worked perfectly for me: 以下对我来说非常合适:

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;
    }
}

Then in fragment/activity when configuring the map: 然后在配置地图时的片段/活动中:

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 is just my custom cluster item class that implements ClusterItem . JobClusterItem只是我实现ClusterItem的自定义集群项类。

The key thing is that there is no attempt to reference the map instance inside the shouldRenderAsCluster method. 关键是没有尝试在shouldRenderAsCluster方法中引用map实例。

You don't need to copypaste the whole class to get mZoom . 你不需要复制全班来获得mZoom You can get the current zoom (not lagged, I hope) using: 您可以使用以下方式获取当前缩放(不希望滞后):

mMap.getCameraPosition().zoom

Your approach of shouldRenderAsCluster() looks correct. 你的shouldRenderAsCluster()看起来是正确的。 Let me know if this doesn't work and we'll check it out. 如果这不起作用,请告诉我们,我们会检查出来。 Welcome to SO. 欢迎来到SO。

Thank you Breeno for pointing me in the right direction. 谢谢Breeno指出我正确的方向。 I would suggest making the listener the onCameraIdleListener as onCameraMoved get called sooooo much. 我建议将监听器设为onCameraIdleListener,因为onCameraMoved会被调用sooooo。 I had already been using the onCameraIdle function for the map, so I did something like this and used Breenos answer to update the current zoom level inside the renderer, just switching out the onCameraMoved with onCameraIdle. 我已经在地图上使用了onCameraIdle函数,所以我做了类似的事情,并使用Breenos答案来更新渲染器内的当前缩放级别,只需使用onCameraIdle切换onCameraMoved。

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();
}

Try this: 试试这个:

@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);
}

Solution Via Reflection 通过反思解决方案

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM