ClusterManager 重绘 Google maps v2 utils 的标记
Posted
技术标签:
【中文标题】ClusterManager 重绘 Google maps v2 utils 的标记【英文标题】:ClusterManager repaint markers of Google maps v2 utils 【发布时间】:2014-04-12 18:59:24 【问题描述】:我正在发出服务器请求,当我收到服务器的响应时,我正在 UI 线程上执行 ClusterManager.addItem()
但这些项目没有在地图上绘制,只有当我进行缩放更新时(+, -) 新添加的项目开始出现。我也尝试调试渲染器,但在我更新放大地图之前不会调用 onBeforeClusterRendered
/ onBeforeClusterItemRendered
。
任何想法如何刷新地图/clusterManager/markers?
MarkerManager markerManager = new MarkerManager(map);
clusterManager = new ClusterManager<TweetClusterItem>(getActivity(), map, markerManager);
clusterManager.setRenderer(new TweetClusterRenderer(getActivity(), map, clusterManager, defaultMarker));
clusterManager.setOnClusterClickListener(this);
clusterManager.setOnClusterInfoWindowClickListener(this);
clusterManager.setOnClusterItemClickListener(this);
clusterManager.setOnClusterItemInfoWindowClickListener(this);
UiSettings uiSettings = map.getUiSettings();
uiSettings.setZoomControlsEnabled(true);
uiSettings.setMyLocationButtonEnabled(false);
map.setOnCameraChangeListener(clusterManager);
map.setOnMarkerClickListener(clusterManager);
map.setOnInfoWindowClickListener(clusterManager);
map.setOnMapClickListener(this);
【问题讨论】:
以下解决方案已过时,还需要重新集群。我找到了一个更好的解决方案及其工作***.com/questions/25684219/… 【参考方案1】:mClusterManager.cluster();
添加新项目后强制重新聚类项目。
【讨论】:
当我在 AsyncTask 完成后执行它时,这对我有用,它会用项目填充 clusterManager。 工作适合我。如果您需要重新创建所有集群,请尝试以下方式:mClusterManager.clearItems(); addItems();(你的逻辑你如何填充管理器) mClusterManager.cluster(); 仅在将项目添加到地图时有效。不是在它们更新并需要重新绘制时【参考方案2】:似乎我找到了解决方法。
ClusterManager 使用渲染器,在这种情况下,它继承自 DefaultClusterRenderer,后者使用内部缓存,即添加到地图的标记缓存。您可以直接访问地图上添加的标记,我不使用信息窗口,所以我添加标记 options.title() 一个 ID 以便以后找到这个标记,所以:
@Override
protected void onBeforeClusterItemRendered(TweetClusterItem item, MarkerOptions markerOptions)
.... Blabla code....
markerOptions.title(Long.toString(tweet.getId()));
.... Blabla code....
当我想重新加载 clusterItem 时,我会调用这个方法:
/**
* Workarround to repaint markers
* @param item item to repaint
*/
public void reloadMarker(TweetClusterItem item)
MarkerManager.Collection markerCollection = clusterManager.getMarkerCollection();
Collection<Marker> markers = markerCollection.getMarkers();
String strId = Long.toString(item.getTweet().getId());
for (Marker m : markers)
if (strId.equals(m.getTitle()))
m.setIcon( ICON TO SET);
break;
也许有点笨拙,但它有效,我没有找到任何其他方法来做到这一点。如果您发现了另一种更好的方法,请分享:)
【讨论】:
clusterManager.getMarkerCollection() 在我的情况下返回一个空列表。但地图将标记显示为集群。 @Sunny 不确定是否为时已晚,但要获得集群,您需要调用 clusterManager.getClusterMarkerCollection() 旧帖子,但这种方法对我有用。您必须记住的想法是集群和标记保存在不同的集合中。更新标记集合中的标记将更改簇外的标记,而簇中的标记将保持不变。为我清除项目或地图导致项目永远不会被重绘。 我想更新标记位置,使用了m.setPosition
函数,它确实更新了它们,但是当我缩小(集群形式)并重新放大(集群分解成单独的标记时,它们的位置被重置)。如何使该职位更新永久化?【参考方案3】:
您可以使用 DefaultClusterRenderer 的 getMarker()、getCluster() 和 getClusterItem()(设置您自己的渲染器以访问渲染器对象)在 O(1) 中获取与其集群或集群项目相对应的特定标记,反之亦然。
根据需要使用这些方法更改项目的标记。
...
DefaultClusterRenderer mRenderer = ...
mClusterManager.setRenderer(mRenderer);
...
public void reloadMarker(ClusterItem item)
mRenderer.getMarker(item).setIcon(YOUR_ICON);
我不建议将它们保存在其他任何地方,因为这些方法返回渲染器的缓存对象。
【讨论】:
【参考方案4】:我遇到了同样的问题。没有一个建议的解决方案对我有用。我创建了一个扩展 DefaultClusterRenderer 的类,并添加了公共方法 updateClusterItem(ClusterItem clusterItem),这将强制重新渲染与该 ClusterItem 关联的标记(适用于集群和集群项目)。
import android.content.Context;
import android.support.annotation.CallSuper;
import android.support.annotation.NonNull;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.maps.android.clustering.Cluster;
import com.google.maps.android.clustering.ClusterItem;
import com.google.maps.android.clustering.ClusterManager;
import com.google.maps.android.clustering.view.DefaultClusterRenderer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public abstract class CustomClusterRenderer<T extends ClusterItem>
extends DefaultClusterRenderer<T>
private ClusterManager<T> mClusterManager;
private Map<T, Marker> mClusterMap = new HashMap<>();
public CustomClusterRenderer(Context context, GoogleMap map,
ClusterManager<T> clusterManager)
super(context, map, clusterManager);
mClusterManager = clusterManager;
@Override
@CallSuper
protected void onClusterItemRendered(T clusterItem, Marker marker)
super.onClusterItemRendered(clusterItem, marker);
mClusterMap.remove(clusterItem);
cleanCache();
@Override
@CallSuper
protected void onClusterRendered(Cluster<T> cluster, Marker marker)
super.onClusterRendered(cluster, marker);
for (T clusterItem : cluster.getItems())
mClusterMap.put(clusterItem, marker);
cleanCache();
public void updateClusterItem(T clusterItem)
Marker marker = getMarker(clusterItem);
boolean isCluster = false;
if (marker == null)
marker = mClusterMap.get(clusterItem);
isCluster = marker != null;
if (marker != null)
MarkerOptions options = getMarkerOptionsFromMarker(marker);
if (isCluster)
Cluster cluster = getCluster(marker);
onBeforeClusterRendered(cluster, options);
else
onBeforeClusterItemRendered(clusterItem, options);
loadMarkerWithMarkerOptions(marker, options);
private void cleanCache()
ArrayList<T> deleteQueue = new ArrayList<>();
Collection<Marker> clusterMarkers = mClusterManager
.getClusterMarkerCollection().getMarkers();
for (T clusterItem : mClusterMap.keySet())
if (!clusterMarkers.contains(mClusterMap.get(clusterItem)))
deleteQueue.add(clusterItem);
for (T clusterItem : deleteQueue)
mClusterMap.remove(clusterItem);
deleteQueue.clear();
private MarkerOptions getMarkerOptionsFromMarker(@NonNull Marker marker)
MarkerOptions options = new MarkerOptions();
options.alpha(marker.getAlpha());
options.draggable(marker.isDraggable());
options.flat(marker.isFlat());
options.position(marker.getPosition());
options.rotation(marker.getRotation());
options.title(marker.getTitle());
options.snippet(marker.getSnippet());
options.visible(marker.isVisible());
options.zIndex(marker.getZIndex());
return options;
private void loadMarkerWithMarkerOptions(@NonNull Marker marker,
@NonNull MarkerOptions options)
marker.setAlpha(options.getAlpha());
marker.setDraggable(options.isDraggable());
marker.setFlat(options.isFlat());
marker.setPosition(options.getPosition());
marker.setRotation(options.getRotation());
marker.setTitle(options.getTitle());
marker.setSnippet(options.getSnippet());
marker.setVisible(options.isVisible());
marker.setZIndex(options.getZIndex());
marker.setIcon(options.getIcon());
marker.setAnchor(options.getAnchorU(), options.getAnchorV());
marker.setInfoWindowAnchor(options.getInfoWindowAnchorU(), options.getInfoWindowAnchorV());
【讨论】:
这是解决这种悲伤的 gmap/集群情况的最佳解决方案 这绝对是这里最好的答案【参考方案5】:我遇到了同样的问题。我在我的 DefaultClusterRenderer 子类的 onBeforeClusterItemRendered 中进行自定义渲染,这也使情况更加复杂。
我的解决方案是创建我的 DefaultClusterRenderer 子类的新实例并再次在 ClusterManager 上调用 setRenderer。这会转储所有缓存的图标并重新创建所有内容。
它是 hacky、蛮力和令人讨厌的低效,但它确实有效。这是我发现的唯一可行的方法,因为该库似乎对此没有明确的支持。
【讨论】:
这种方法对我有用。重新分配我的自定义渲染器实例可以解决问题,但感觉不对,感觉可能会导致内存泄漏。调用 mClusterManager.cluster() 也可以,而且似乎是一种更好的方法。【参考方案6】:mClusterManager.cluster();
不适合我
尽管如此:
if (mMap != null)
CameraPosition currentCameraPosition = mMap.getCameraPosition();
mMap.moveCamera(CameraUpdateFactory.newCameraPosition(currentCameraPosition));
这触发了 onCameraChange 调用,我已经在其中执行 mClusterManager.clearItems()... mClusterManager.addItem(..) - 用于可见区域内的对象... mClusterManager.cluster()
我的情况是,当返回显示地图的片段时,图钉正在消失(- 仅在某些设备上,例如 Nexus 7,没有自动调用 OnCameraChange)
【讨论】:
你能发布一个在 onCameraChange 中使用的代码示例吗?我希望只有在可见区域中渲染标记才能提高我的应用的性能【参考方案7】:我注意到标记仅在放大或缩小时出现,因此我使用所有旧值设置了一个新的相机位置,除了轻微的缩放变化。
CameraPosition currentCameraPosition = googleMap.getCameraPosition();
CameraPosition cameraPosition = new CameraPosition(currentCameraPosition.target, currentCameraPosition.zoom - .1f, currentCameraPosition.tilt, currentCameraPosition.bearing);
googleMap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
【讨论】:
【参考方案8】:我使用扩展 DefaultClusterRenderer 的 CustomRenderer 的解决方案
protected void onClusterItemRendered(T clusterItem, Marker marker)
marker.setIcon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN));
【讨论】:
以上是关于ClusterManager 重绘 Google maps v2 utils 的标记的主要内容,如果未能解决你的问题,请参考以下文章
ClusterManager onMarkerClickListener 用于非聚集标记
如何在 android 中获得 ClusterManager 点击和 ClusterManager 项目点击