Search code examples
androidgoogle-mapsrendermarkerclusterer

Best way to render only the visible cluster items on a google map


I have a map fragment that is handled by google's cluster manager that I configured with my custom cluster renderer extends DefaultClusterRenderer.

I have overritten the functions onBeforeClusterItemRendered and onBeforeClusterRendered to be able to diplay my pictures:

enter image description here

Now If the user zooms in it makes no sense to render the items that are not in the visible area. It's very easy to find out if the item is in the visible area:

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

But if I skip the rendering if the item is not currently visible, it will be empty when the user scrolls on the map.

So who knows how to get an event if the user scrolls and how to re render the items that are not in the visible bounds? (switchen from visible to non visible and vice versa)?

(Sorry for my bad English)


Solution

  • Here is my solution. It works very well and renders only the visible items. I use the camera changed listener to re render the items that became visible now:

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