【问题标题】:ClusterManager repaint markers of Google maps v2 utilsClusterManager 重绘 Google maps v2 utils 的标记
【发布时间】:2023-03-05 09:37:01
【问题描述】:

我正在发出服务器请求,当我收到服务器的响应时,我正在 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);

【问题讨论】:

标签: android android-maps-v2 android-maps-utils


【解决方案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));
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-06-14
        • 1970-01-01
        • 2015-09-19
        • 2013-01-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多