在Google地图上仅渲染可见群集项的最佳方法

时间:2016-07-30 12:56:44

标签: android google-maps render markerclusterer

我有一个地图片段,由我使用自定义群集渲染器extends DefaultClusterRenderer配置的Google群集管理器处理。

我已经过度强调了onBeforeClusterItemRenderedonBeforeClusterRendered功能,以便能够显示我的照片:

enter image description here

现在,如果用户放大,则渲染不在可见区域内的项目是没有意义的。 很容易发现物品是否在可见区域:

private Boolean isInBounds(LatLng position) {
    return map.getProjection().getVisibleRegion().latLngBounds.contains(position);
}

但如果我跳过渲染,如果该项当前不可见,则当用户在地图上滚动时它将为空。

那么,如果用户滚动以及如何重新渲染不在可见边界内的项目,谁知道如何获取事件? (从可见到非可见的转换,反之亦然)?

(抱歉我的英语不好)

2 个答案:

答案 0 :(得分:4)

这是我的解决方案。它工作得很好,只渲染可见的项目。 我使用相机更改的侦听器重新渲染现在可见的项目:

private void onBeforeClusterOrClusterItemRendered(final Cluster<MediaItem> cluster, final MediaItem mediaItem, final MarkerOptions markerOption
    if(!isAdded())
        return;

    // In visible area?
    Marker marker = cluster == null ? getMarker(mediaItem) : getMarker(cluster);
    Boolean isInBounds = isInBounds(marker != null ? marker.getPosition() : mediaItem.getPosition(), null);

    if(isInBounds) {
        // ...
    }
}

private Boolean isInBounds(LatLng position, LatLngBounds latLngBounds) {
    return (latLngBounds == null ? mMap.getProjection().getVisibleRegion().latLngBounds : latLngBounds).contains(position);
}

@Override
protected void onBeforeClusterItemRendered(final MediaItem mediaItem, final MarkerOptions markerOptions) {
    onBeforeClusterOrClusterItemRendered(null, mediaItem, markerOptions);
}

@Override
protected void onBeforeClusterRendered(final Cluster<MediaItem> cluster, final MarkerOptions markerOptions) {
    final MediaItem mediaItem = MediaPicker.getBestRated(new ArrayList<>(cluster.getItems()));
    onBeforeClusterOrClusterItemRendered(cluster, mediaItem, markerOptions);
}

...

// Re render
mMap.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() {
    @Override
    public void onCameraChange(CameraPosition cameraPosition) {
        mClusterManager.onCameraChange(cameraPosition);
        final LatLngBounds latLngBounds = mMap.getProjection().getVisibleRegion().latLngBounds;

        // Cluster only
        Collection<Marker> clusters = mClusterManager.getClusterMarkerCollection().getMarkers();
        for(Marker marker : clusters) {
            if(isInBounds(marker.getPosition(), latLngBounds))
                onBeforeClusterRendered(getCluster(marker), new MarkerOptions());
        }

        // Cluster item only
        Collection<Marker> markers = mClusterManager.getMarkerCollection().getMarkers();
        for(Marker marker : markers) {
            if(isInBounds(marker.getPosition(), latLngBounds))
                onBeforeClusterItemRendered(getClusterItem(marker), new MarkerOptions());
        }
    }
});

答案 1 :(得分:3)

我有类似的问题。我跟踪用户的初始位置并显示他周围的地图标记。如果用户选择查看外部初始缩放,我会下载其他标记。实施:

map.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() {

            @Override
            public void onCameraChange(CameraPosition cameraPosition) {
                setCurrentRadius();
                viewCenter = cameraPosition.target;
                if (isNewGrounds(viewCenter, viewRadius)) {
                    downloadExtraPrinters(viewCenter,viewRadius);
                }
                myClusterManager.onCameraChange(cameraPosition);
            }
        });

   private void setCurrentRadius() {
        Projection projection = map.getProjection();
        VisibleRegion currentView = projection.getVisibleRegion();
        LatLng cameraCenter = map.getCameraPosition().target;
        float[] projectionRadius = new float[1];
        Location.distanceBetween(currentView.farLeft.latitude, currentView.farLeft.longitude, cameraCenter.latitude, cameraCenter.longitude, projectionRadius);
        viewRadius = Math.round((projectionRadius[0] / 1000.0f) + 0.5f);
    }

 /** Method checks if camera goes outside bounds of previously downloaded area **/
    protected boolean isNewGrounds(LatLng center, int radius) {
        //Check if it is the first time to update
        if (coveredGroundsCenter== null) {

            coveredGroundsCenter=center;
            coveredGroundsRadius= (int)(radius * EXTRA_RADIUS);

            return true;
        }else {
            float[] centerDistance = new float[1];
            Location.distanceBetween(coveredGroundsCenter.latitude, coveredGroundsCenter.longitude, center.latitude, center.longitude, centerDistance);

            int criticalDistance = (int) Math.round((centerDistance[0] / 1000.0f) + 0.5f) + radius;

            if (coveredGroundsRadius >= criticalDistance) {
                return false;
            } else {
                coveredGroundsCenter = center;
                coveredGroundsRadius = (int) (radius * EXTRA_RADIUS);
                return true;
            }
        }
    }

EXTRA_RADIUS是一个常量,我用它在可见地图区域外有一个小的边距,因此最小的相机移动不会导致我的地图下载和重新渲染。我选择这个边距是当前半径的50%:

 private static final double EXTRA_RADIUS=1.5;
 private LatLng coveredGroundsCenter;
 private int coveredGroundsRadius;
 private LatLng viewCenter;