Denny Weinberg Denny Weinberg - 4 months ago 168
Android Question

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)

Answer

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;

    // Placeholder. If we do not do this, there will be a default red pin while the picture is loading (async Glide)
    markerOptions.icon(mPlaceholderBitmapDescriptor);

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

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