Android Google Maps Utils ClusterManager Change Icon Text, Size And Color

Hack DefaultClusterRenderer.

Google Maps Utils Cluster Manager cluster markers together into clusters (round circle icon with number) to avoid showing too many markers.

The ClusterManager helps you manage multiple markers at different zoom levels. This means you can put a large number of markers on a map without making the map hard to read. When a user views the map at a high zoom level, the individual markers show on the map. When the user zooms out to a lower zoom level, the markers gather together into clusters, to make viewing the map easier.

This article focus on how change the text, size and color of the cluster icons.

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.

  • Edit makeSquareTextView to change font size, style and padding, which would affect the cluster oval icon's size. Remember to remove mIconGenerator.setTextAppearance to prevent text style to be overwritten.
  • Edit getColor to change the cluster oval icon's background color.
  • Edit onBeforeClusterRendered or getClusterText to change cluster oval icon's text.
public class MyClusterRenderer<T extends ClusterItem> implements ClusterRenderer<T> {    ...    public NumberClusterRenderer(Context context, GoogleMap map, ClusterManager<T> clusterManager) {        mMap = map;        mAnimate = true;        mDensity = context.getResources().getDisplayMetrics().density;        mIconGenerator = new IconGenerator(context);        mIconGenerator.setContentView(makeSquareTextView(context));        // comment this line to prevent text style being applied and overwriting makeSquareTextView settings        // mIconGenerator.setTextAppearance(R.style.amu_ClusterIcon_TextAppearance);        mIconGenerator.setBackground(makeClusterBackground());        mClusterManager = clusterManager;    }    ...    // the oval shape of cluster icon size depends mostly on the text and padding size    private SquareTextView makeSquareTextView(Context context) {        SquareTextView squareTextView = new SquareTextView(context);        // added the following 3 lines to change text size, color and bold        // I make the text smaller, color and bold is required since we removed R.style.amu_ClusterIcon_TextAppearance        squareTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10);        squareTextView.setTextColor(Color.WHITE);        squareTextView.setTypeface(null, Typeface.BOLD);        ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);        squareTextView.setLayoutParams(layoutParams);        squareTextView.setId(R.id.amu_text);        // initial is 12dp, I resize the round shape padding to 6dp        int twelveDpi = (int) (6 * mDensity);        squareTextView.setPadding(twelveDpi, twelveDpi, twelveDpi, twelveDpi);        return squareTextView;    }    ...    protected int getColor(int clusterSize) {        /*        final float hueRange = 220;        final float sizeRange = 300;        final float size = Math.min(clusterSize, sizeRange);        final float hue = (sizeRange - size) * (sizeRange - size) / (sizeRange * sizeRange) * hueRange;        return Color.HSVToColor(new float[]{                hue, 1f, .6f        });         */        // I use Cyan color palette: https://material.io/guidelines/style/color.html#color-color-palette        // refer to variable BUCKETS for available cluster size        String color = "#80DEEA";        switch(clusterSize) {            case 10:                color = "#4DD0E1";                break;            case 20:                color = "#26C6DA";                break;            case 50:                color = "#00BCD4";                break;            case 100:                color = "#00ACC1";                break;            case 200:                color = "#0097A7";                break;            case 500:                color = "#00838F";                break;            case 1000:                color = "#006064";                break;        }        return Color.parseColor(color);    }    ...    protected void onBeforeClusterRendered(Cluster<T> cluster, MarkerOptions markerOptions) {        int bucket = getBucket(cluster);        BitmapDescriptor descriptor = mIcons.get(bucket);        if (descriptor == null) {            mColoredCircleBackground.getPaint().setColor(getColor(bucket));            // you can edit/replace getClusterText to change text of cluster icon            descriptor = BitmapDescriptorFactory.fromBitmap(mIconGenerator.makeIcon(getClusterText(bucket)));            mIcons.put(bucket, descriptor);        }        // TODO: consider adding anchor(.5, .5) (Individual markers will overlap more often)        markerOptions.icon(descriptor);    }    ...    }

Load our custom MyClusterRenderer.

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

❤️ Is this article helpful?

Buy me a coffee ☕ or support my work via PayPal to keep this space 🖖 and ad-free.

Do send some 💖 to @d_luaz or share this article.

✨ By Desmond Lua

A dream boy who enjoys making apps, travelling and making youtube videos. Follow me on @d_luaz

👶 Apps I built

Travelopy - discover travel places in Malaysia, Singapore, Taiwan, Japan.