缺省集群渲染器(DefaultClusterRenderer)在缩放时返回null的标记(Marker)。

10

我想在点击时更改聚合标记的背景。我通过以下方式实现:

@Override
onClusterClick(Cluster<MyObject> cluster) {
    Marker marker = renderer.getMarker(cluster);
    marker.setIcon(....);
}

除了一种情况,这个方法很好用:当我放大或缩小时,聚类标记的数量不会改变。例如,如果我有一个15个聚类和5个聚类,然后缩放一级,同样的两个聚类保持不变。现在点击其中之一,renderer.getMarker(cluster)返回null。如果他们在缩放后重新聚类,getMarker就不是null了。

我的DefaultClusterRenderer如下所示。我检查了onClusteredRendered上的marker并且它从未为null。这是DefaultClusterRenderer中的错误还是我应该做些其他的事情?

private class MyRenderer extends DefaultClusterRenderer<MyObject> {

    private IconGenerator iconGenerator;
    private float density;

    public MyRenderer(Context context, GoogleMap map, ClusterManager<MyObject> clusterManager) {
        super(context, map, clusterManager);
        density = context.getResources().getDisplayMetrics().density;
    }

    @Override
    protected void onBeforeClusterItemRendered(MyObject item, MarkerOptions markerOptions) {
        markerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.my_pin));
    }

    @Override
    protected void onBeforeClusterRendered(Cluster<MyObject> cluster, MarkerOptions markerOptions) {
        if(iconGenerator == null) {
            iconGenerator = new IconGenerator(getActivity());
            iconGenerator.setContentView(makeTextView(getActivity()));
        }
        iconGenerator.setBackground(makeBackground(false));

        markerOptions.icon(BitmapDescriptorFactory.fromBitmap(iconGenerator.makeIcon(String.valueOf(cluster.getSize()))));
    }

    @Override
    protected void onClusterRendered(Cluster<MyObject> cluster, Marker marker) {
        super.onClusterRendered(cluster, marker);
        // Marker is never null here

    }

    @Override
    protected boolean shouldRenderAsCluster(Cluster<MyObject> cluster) {
        return cluster.getSize() > 1;
    }

    private ShapeDrawable makeBackground(boolean isClicked) {
        ShapeDrawable background = new ShapeDrawable(new OvalShape());
        background.setColorFilter(ContextCompat.getColor(getActivity(),
                isClicked ? R.color.cluster_marker_clicked : R.color.cluster_marker_unclicked), PorterDuff.Mode.SRC_ATOP);

        return background;
    }

    private SquareTextView makeTextView(Context context) {
        SquareTextView squareTextView = new SquareTextView(context);

        ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(-2, -2);
        squareTextView.setLayoutParams(layoutParams);
        squareTextView.setTextColor(ContextCompat.getColor(getActivity(), R.color.white));

        squareTextView.setTypeface(Utils.getFontBold(getActivity()));

        squareTextView.setId(com.google.maps.android.R.id.text);
        int twelveDpi = (int) (12.0F * density);
        squareTextView.setPadding(twelveDpi, twelveDpi, twelveDpi, twelveDpi);

        return squareTextView;
    }

    public IconGenerator getIconGenerator(boolean isClicked) {
        iconGenerator.setBackground(makeBackground(isClicked));
        return iconGenerator;
    }
}

初始化集群管理器:

    final ClusterManager<MyObject> mClusterManager = new ClusterManager<>(getActivity(), googleMap);
    mClusterManager.addItems(items);

    renderer = new CustomRenderer(getActivity(), googleMap, mClusterManager);
    mClusterManager.setRenderer(renderer);
    mClusterManager.cluster();

    mClusterManager.setOnClusterItemClickListener(this);

    googleMap.setOnMarkerClickListener(mClusterManager);

@安东尼奥:这个初始化对我起作用:

public class MapsActivity extends FragmentActivity
        implements ClusterManager.OnClusterClickListener<MyObject> {

    // ...

    private void setUpClusterer() {
        googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(51.503186, -0.126446), 10));

        mClusterManager = new ClusterManager<MyObject>(this, googleMap);
        mClusterManager.setOnClusterClickListener(this);
        renderer = new MyRenderer(this, googleMap, mClusterManager);
        mClusterManager.setRenderer(renderer);

        googleMap.setOnCameraChangeListener(mClusterManager);
        googleMap.setOnMarkerClickListener(mClusterManager);

        addItems();
    }

    private void addItems() {
        // Set some lat/lng coordinates to start with.
        double lat = 51.5145160;
        double lng = -0.1270060;

        // Add ten cluster items in close proximity, for purposes of this example.
        for (int i = 0; i < 10; i++) {
            double offset = i / 60d;
            lat = lat + offset;
            lng = lng + offset;
            MyObject offsetItem = new MyObject(lat, lng);
            mClusterManager.addItem(offsetItem);
        }
    }

    @Override
    public boolean onClusterClick(final Cluster<MyObject> cluster) {
        Marker marker = renderer.getMarker(cluster);
        marker.setIcon(BitmapDescriptorFactory.fromResource(R.drawable.my_newpin));

        return true;
    }
}

我无法通过演示应用程序重现您的行为。 您是如何将项目添加到集群中的? 我敢打赌这更多是一个生命周期问题,而不是您的Renderer的问题。 我还会说,当调用renderer.getMarker(cluster);时,您会收到一个空的“标记”,因为您在 onClusterClick(Cluster<MyObject> cluster) 接收到的集群是空的。 - antonio
集群永远不会为空。我在初始化“ClusterManager”时更新了上面的代码。 - ono
好的,让我使用你的初始化代码测试我的示例的行为。 - antonio
我已经使用适合我的初始化方式编辑了你的问题。在我的情况下,我使用 OnClusterClickListener 而不是使用 OnClusterItemClickListener - antonio
@antonio 不确定为什么无法返回标记。我刚刚添加了一个解决方法。 - ono
显示剩余2条评论
1个回答

3

在上述情况下,无法通过renderer.getMarker(cluster)获取标记。一个解决方法是创建:

Map <Cluster<MyObject>, Marker> clusterMarkerMap = new HashMap<>();

然后将它们添加到 DefaultClusterRenderer 回调中,因为在那里标记永远不为空:

@Override
protected void onClusterRendered(Cluster<MyObject> cluster, Marker marker) {
    super.onClusterRendered(cluster, marker);
    clusterMarkerMap.put(cluster, marker);
}

由于 DefaultClusterManager 在摄像机位置发生变化时清除它们,因此在创建新的聚合标记之前,请清除聚合标记地图:

 googleMap.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() {
        @Override
        public void onCameraChange(CameraPosition cameraPosition) {
            // Clear the map here because the markers will be recreated
            // when the manager is notified of a (zoom level) camera change
            if(zoomLevelChanged)
                 clusterMarkerMap.clear();
            mClusterManager.onCameraChange(cameraPosition);
        }
    });

现在我可以成功获取标记 clusterMarkerMap.get(cluster)


我有同样的问题,你有更详细的onCameraChange代码吗? - nikeru8
@nikeru8 不好意思,我不再有那段代码的访问权限了。 - ono

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接