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

Posted

技术标签:

【中文标题】使用 Googles android-maps-utils 在最大缩放级别禁用集群【英文标题】:Disable clustering at max zoom level with Googles android-maps-utils 【发布时间】:2015-12-30 18:53:54 【问题描述】:

我正在使用来自android-maps-utils 的聚类对 Android 中的 Google 地图上的标记进行聚类。我想在地图处于最大缩放级别时禁用集群(即,如果地图处于最大缩放级别,则始终渲染单个 ClusterItem,否则集群正常)。

我几乎可以通过在扩展 DefaultClusterRenderer 的自定义类中对 shouldRenderAsCluster() 中的缩放级别进行测试来使其正常工作。但是,我的解决方案比实际缩放级别落后了一步。例如,如果地图的最大缩放级别为 21 级,并且用户从 20 级放大到 21 级,则 shouldRenderAsCluster 中的检查将获得当前缩放级别 20。如果用户随后缩小到 20 级,检查将达到 21 级。ClusterItems 被渲染为我想要的单个项目,但是一个缩放操作为时已晚。

我从 DefaultClusterRenderer 中设置的变量 mZoom 中获得“当前缩放”(显然不是当前的)。

这是代码:

public class UserClusterRenderer extends PosMapDefaultClusterRenderer<UserClusterItem> 

    // ...

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

变量 mZoom 和 mMap 在 DefaultClusterRenderer 中设置。因为他们在那里有私有访问权限,所以我制作了一个名为 PosMapDefaultClusterRenderer 的 DefaultClusterRenderer 副本。唯一的区别是 mZoom 和 mMap 被声明为 protected,因此它们可以在 UserClusterRenderer 中访问。

为什么 mZoom 落后一个缩放动作?有没有办法获得渲染集群的真实缩放级别?

缩放是通过使用来自 cameraPosition 的 cameraUpdate 调用 animateCamera 来完成的。

这也是我在 *** 上的第一个问题,因此欢迎任何关于标签、格式等的输入。

编辑: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;
    

【问题讨论】:

你解决了吗? 【参考方案1】:

@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
        return super.shouldRenderAsCluster(cluster) && currentZoomLevel < maxZoomLevel;
    

然后在fragment/activity中配置地图时:

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 方法中没有尝试引用地图实例。

【讨论】:

对 Breeno 很有帮助! 不错的解决方案。 shouldRenderAsCluster() 可以简化为 return super.shouldRenderAsCluster(cluster) &amp;&amp; currentZoomLevel &lt; maxZoomLevel 好建议@SergeyStasishin - 更新了我的例子,谢谢。【参考方案2】:

感谢 Breeno 为我指明了正确的方向。我建议让监听器成为 onCameraIdleListener,因为 onCameraMoved 被调用的次数太多了。我已经在地图上使用了 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();

【讨论】:

【参考方案3】:

您无需复制粘贴整个班级即可获得mZoom。您可以使用以下方法获得当前缩放(我希望不会滞后):

mMap.getCameraPosition().zoom

您的shouldRenderAsCluster() 方法看起来是正确的。如果这不起作用,请告诉我,我们会检查一下。欢迎来到 SO。

【讨论】:

谢谢,通过相机从地图获取当前缩放解决了滞后问题。使用工作代码更新了答案。请注意,我仍然需要存储对地图的引用,因为 mMap 在 DefaultClusterRenderer 中具有私有访问权限。 这应该不会导致问题,因为您可以看到默认实现也在存储它。 protected boolean shouldRenderAsCluster(Cluster cluster) return map.getCameraPosition().zoom 确实,在动画期间访问地图摄像头位置似乎会因java.lang.IllegalStateException: Not on the main thread 而崩溃。 抱歉,摄像头位置 API 随时间而变化。【参考方案4】:

试试这个:

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

通过反射解决

【讨论】:

以上是关于使用 Googles android-maps-utils 在最大缩放级别禁用集群的主要内容,如果未能解决你的问题,请参考以下文章

Googles OR-Tools Modules for CSP 和 VRP 使用哪个求解器?

php 我创建的缩小php脚本,以最大限度地提高Googles页面速度得分

python Google文本到Python演讲(TTS),更多信息,请访问http://alexsleat.co.uk/2011/11/14/python-making-use-of-googles

Google oAuth登录 - 如何仅允许列入白名单的电子邮件登录我的应用

URL缩短器Api

谷歌排行榜 ApiException