Assuming you are using Google Maps Utils Cluster Manager to display markers as clusters and you would like the map to display all the clusters within the map view.
Google Maps fit all markers
You could utilize the Google Maps way of fitting all markers within the map view (adjustng zoom and position).
// if builder doesn't include any item, an exception shall be thrownif (clusterItems.size() > 0) { LatLngBounds.Builder builder = new LatLngBounds.Builder(); for (ClusterItem item : clusterItems) { builder.include(item.getPosition()); } LatLngBounds bounds = builder.build(); // padding in pixels int padding = 20; // use animateCamera if animation is required map.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, padding)); if (clusterItems.size() == 1) { // you might want to a custom zoom level if there is only 1 item map.moveCamera(CameraUpdateFactory.zoomTo(15)); }}
If your markers or clusters are spread across the world (e.g. Japan, Europe & US), this method might not work very well as Google Maps can only show about half the world in its view.
Hack DefaultClusterRenderer
DefaultClusterRenderer does not expose most of its variables and functions (private only), so the only way to expose them is to copy the code and modify them with your own implementation.
Copy the code of DefaultClusterRenderer and rename the class as MyClusterRenderer. Add the following method to explose all the clusters.
public class MyClusterRenderer<T extends ClusterItem> implements ClusterRenderer<T> { ... public Collection<Cluster<T>> getClusters() { return mClusterToMarker.keySet(); } ...}
Rather than looping all the markers to fit all clusters to be displayed in the map view, we shall loop through the clusters instead to get the LatLngBounds
.
mapFragment.getMapAsync(new OnMapReadyCallback() { @Override public void onMapReady(final GoogleMap map) { ClusterManager clusterManager = new ClusterManager(activity, map); final MyClusterRenderer renderer = new NumberClusterRenderer(activity, map, clusterManager); // use this to show cluster only without markers renderer.setMinClusterSize(0); clusterManager.setRenderer(renderer); clusterManager.addItems(items); // clusters are not loaded until MapLoadedCallback map.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() { @Override public void onMapLoaded() { Collection<Cluster> clusters = renderer.getClusters(); if (clusters.size() > 0) { LatLngBounds.Builder builder = new LatLngBounds.Builder(); for (Cluster cluster : clusters) { builder.include(cluster.getPosition()); } LatLngBounds bounds = builder.build(); // use 50dip to cater for the cluster icon size float density = context.getResources().getDisplayMetrics().density; int padding = (int) (50 * density); CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, Helper.convertDpToPx(context, padding)); map.moveCamera(cu); } } }); }});
Fit clusters and markers around the world
If the clusters are spread across the world, this method might not work very well as Google Maps can only show about half the world in its view.
First, we need to check if the map view can fit all the clusters. If it can't fit, we shall focus the map view on the largest cluster while maintaining zoom (most likely the widest zoom).
mapFragment.getMapAsync(new OnMapReadyCallback() { @Override public void onMapReady(final GoogleMap map) { ClusterManager clusterManager = new ClusterManager(activity, map); final MyClusterRenderer renderer = new NumberClusterRenderer(activity, map, clusterManager); // use this to show cluster only without markers renderer.setMinClusterSize(0); clusterManager.setRenderer(renderer); clusterManager.addItems(items); // clusters are not loaded until MapLoadedCallback map.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() { @Override public void onMapLoaded() { Collection<Cluster> clusters = renderer.getClusters(); if (clusters.size() > 0) { LatLngBounds.Builder builder = new LatLngBounds.Builder(); for (Cluster cluster : clusters) { builder.include(cluster.getPosition()); } LatLngBounds bounds = builder.build(); // use 50dip to cater for the cluster icon size float density = context.getResources().getDisplayMetrics().density; int padding = (int) (50 * density); CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, Helper.convertDpToPx(context, padding)); map.moveCamera(cu); // check can fit all the clusters LatLngBounds mapBounds = map.getProjection().getVisibleRegion().latLngBounds; if (mapBounds.contains(bounds.northeast) && mapBounds.contains(bounds.southwest)) { Log.d(TAG, "Fit OK"); } else { Log.d(TAG, "Fit FAIL"); // loop all to find the biggest cluster Cluster maxCluster = null; for (Cluster cluster : clusters) { if (maxCluster == null || cluster.getSize() > maxCluster.getSize()) { maxCluster = cluster; } } // focus on biggest cluster if (maxCluster != null) { cu = CameraUpdateFactory.newLatLng(maxCluster.getPosition()); map.moveCamera(cu); } } } } }); }});