ClusterManager重绘Google map v2 utils的标记

时间:2014-03-09 19:45:22

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

我正在发出服务器请求,当我收到来自服务器的请求时,我正在Ui Thread上执行一个ClusterManager.addItem(),但是这些项目不会在地图中绘制,只有当我进行缩放更新时(+ , - )正在显示。此外,我尝试调试渲染器,但是直到我更新地图中的缩放才调用onBeforeClusterRendered / onBeforeClusterItemRendered。 有关如何刷新map / 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);

8 个答案:

答案 0 :(得分:25)

mClusterManager.cluster();

在添加新项目后强制重新聚类项目。

答案 1 :(得分:15)

似乎我找到了解决方法。

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

    }

也许有点hacky但是它有效并且我没有找到任何其他方法来做到这一点。如果您找到了另一种更好的方法,请分享:)

答案 2 :(得分:2)

我遇到了同样的问题。我在DefaultClusterRenderer子类上的onBeforeClusterItemRendered中进行自定义渲染也使事情更加复杂。

我的解决方案是创建DefaultClusterRenderer子类的新实例,并再次在ClusterManager上调用setRenderer。这会转储所有缓存的图标&amp;重建一切。

这是hacky,蛮力和恼人的低效率,但确实有效。这是我发现的唯一方法,因为图书馆似乎没有明确的支持。

答案 3 :(得分:2)

您可以使用DefaultClusterRenderer的getMarker(),getCluster()和getClusterItem()(设置您自己的渲染器来访问渲染器对象),在O(1)中获取与其群集或群集项对应的特定标记,反之亦然。 / p>

使用这些方法可以在需要时更改商品的标记。

   ...
   DefaultClusterRenderer mRenderer = ...
   mClusterManager.setRenderer(mRenderer);
   ...

public void reloadMarker(ClusterItem item) {
    mRenderer.getMarker(item).setIcon(YOUR_ICON);
}

我不建议将它们保存在其他任何地方,因为这些方法会返回渲染器的缓存对象。

答案 4 :(得分:2)

mClusterManager.cluster();对我不起作用

但是这样做了:

if (mMap != null) {
    CameraPosition currentCameraPosition = mMap.getCameraPosition();
    mMap.moveCamera(CameraUpdateFactory.newCameraPosition(currentCameraPosition));
}

这触发了一个onCameraChange调用,我已经在这里调用mClusterManager.clearItems()... mClusterManager.addItem(..) - 用于可见区域内的对象... mClusterManager.cluster()

我的背景是当返回到显示地图的片段时,引脚正在消失( - 仅在某些设备上,例如Nexus 7,没有自动调用OnCameraChange)

答案 5 :(得分:2)

我遇到了同样的问题。没有一个建议的解决方案适合我。我创建了一个扩展DefaultClusterRenderer的类,并添加了公共方法updateClusterItem(ClusterItem clusterItem),它将强制重新呈现与该ClusterItem关联的Marker(适用于集群和集群项)。

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

}

答案 6 :(得分:0)

我注意到标记仅在放大或缩小时才会显示,因此我将所有旧值设置为新的相机位置,只是略微改变了变焦。

    CameraPosition currentCameraPosition = googleMap.getCameraPosition();
    CameraPosition cameraPosition = new CameraPosition(currentCameraPosition.target, currentCameraPosition.zoom - .1f, currentCameraPosition.tilt, currentCameraPosition.bearing);
    googleMap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));

答案 7 :(得分:-1)

我的解决方案使用了一个扩展DefaultClusterRenderer的CustomRenderer

 protected void onClusterItemRendered(T clusterItem, Marker marker) {
    marker.setIcon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN));
}