使用 Googles android-maps-utils 在最大缩放级别禁用聚类
Disable clustering at max zoom level with Googles android-maps-utils
我正在 Android 中的 Google 地图上使用来自 android-maps-utils 的聚类对标记进行聚类。我想在地图处于最大缩放级别时禁用聚类(即,如果地图处于最大缩放级别,则始终呈现单个 ClusterItems,否则正常聚类)。
我几乎可以通过在扩展 DefaultClusterRenderer 的自定义 class 中对 shouldRenderAsCluster() 中的缩放级别进行测试来使其正常工作。但是,我的解决方案比实际缩放级别落后一步。例如,如果地图的最大缩放级别为 21 级,并且用户从 20 级放大到 21 级,则 shouldRenderAsCluster 中的检查将获得当前缩放级别 20。如果用户然后缩小到 20 级,检查将达到 21 级。ClusterItems 像我想要的那样呈现为单独的项目,但一个缩放动作为时已晚。
我从 DefaultClusterRenderer 中设置的变量 mZoom 得到 "Current Zoom"(显然不是当前的)。
这是代码:
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 被声明为受保护的,因此它们可以在 UserClusterRenderer 中访问。
为什么 mZoom 落后一个缩放动作?有没有办法获得正在渲染的集群的真实缩放级别?
缩放是通过使用来自 cameraPosition 的 cameraUpdate 调用 animateCamera 来完成的。
这也是我在 Whosebug 上的第一个问题,因此欢迎任何关于标签、格式等的输入。
编辑: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;
}
}
您无需复制粘贴整个 class 即可获得 mZoom
。您可以使用以下方式获取当前缩放(我希望没有滞后):
mMap.getCameraPosition().zoom
您 shouldRenderAsCluster()
的方法看起来是正确的。如果这不起作用,请告诉我,我们会检查一下。欢迎来到 SO。
@Marc D 我在线程异常方面遇到了同样的问题,上面提出的解决方案对我不起作用。
为了解决这个问题,我将初始缩放级别和所需的最大缩放级别作为参数传递到自定义渲染器中,然后让自定义渲染器 class 实现 GoogleMap.onCameraMoveListener 以便它可以进一步更改缩放级别,并将地图上的 onCameraMoveListener 设置为我的自定义渲染器实例 class.
以下对我来说非常有效:
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.
的自定义集群项 class
关键是没有尝试在 shouldRenderAsCluster 方法中引用地图实例。
感谢 Breeno 为我指明了正确的方向。我建议让监听器成为 onCameraIdleListener,因为 onCameraMoved 被调用得太多了。我已经为地图使用了 onCameraIdle 函数,所以我做了类似的事情并使用 Breenos 答案更新渲染器内的当前缩放级别,只需将 onCameraMoved 切换为 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();
}
试试这个:
@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);
}
通过反射解决
我正在 Android 中的 Google 地图上使用来自 android-maps-utils 的聚类对标记进行聚类。我想在地图处于最大缩放级别时禁用聚类(即,如果地图处于最大缩放级别,则始终呈现单个 ClusterItems,否则正常聚类)。
我几乎可以通过在扩展 DefaultClusterRenderer 的自定义 class 中对 shouldRenderAsCluster() 中的缩放级别进行测试来使其正常工作。但是,我的解决方案比实际缩放级别落后一步。例如,如果地图的最大缩放级别为 21 级,并且用户从 20 级放大到 21 级,则 shouldRenderAsCluster 中的检查将获得当前缩放级别 20。如果用户然后缩小到 20 级,检查将达到 21 级。ClusterItems 像我想要的那样呈现为单独的项目,但一个缩放动作为时已晚。
我从 DefaultClusterRenderer 中设置的变量 mZoom 得到 "Current Zoom"(显然不是当前的)。
这是代码:
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 被声明为受保护的,因此它们可以在 UserClusterRenderer 中访问。
为什么 mZoom 落后一个缩放动作?有没有办法获得正在渲染的集群的真实缩放级别?
缩放是通过使用来自 cameraPosition 的 cameraUpdate 调用 animateCamera 来完成的。
这也是我在 Whosebug 上的第一个问题,因此欢迎任何关于标签、格式等的输入。
编辑: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;
}
}
您无需复制粘贴整个 class 即可获得 mZoom
。您可以使用以下方式获取当前缩放(我希望没有滞后):
mMap.getCameraPosition().zoom
您 shouldRenderAsCluster()
的方法看起来是正确的。如果这不起作用,请告诉我,我们会检查一下。欢迎来到 SO。
@Marc D 我在线程异常方面遇到了同样的问题,上面提出的解决方案对我不起作用。
为了解决这个问题,我将初始缩放级别和所需的最大缩放级别作为参数传递到自定义渲染器中,然后让自定义渲染器 class 实现 GoogleMap.onCameraMoveListener 以便它可以进一步更改缩放级别,并将地图上的 onCameraMoveListener 设置为我的自定义渲染器实例 class.
以下对我来说非常有效:
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.
的自定义集群项 class关键是没有尝试在 shouldRenderAsCluster 方法中引用地图实例。
感谢 Breeno 为我指明了正确的方向。我建议让监听器成为 onCameraIdleListener,因为 onCameraMoved 被调用得太多了。我已经为地图使用了 onCameraIdle 函数,所以我做了类似的事情并使用 Breenos 答案更新渲染器内的当前缩放级别,只需将 onCameraMoved 切换为 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();
}
试试这个:
@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);
}
通过反射解决