Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android maps utils cluster icon color

Is there any method to change the background color of the cluster item? (the one that displays the count of the markers, like 100+, 200+ ...). I tried to look into the source code of the ClusterManager but could not find any option to change the color, but maybe someone here knows how to do that. I basically want to "materialify" those colors a bit.

like image 935
qwertz Avatar asked Jun 21 '15 18:06

qwertz


4 Answers

I was able to get a rough implementation working by using this demo from the library samples as a guide.

I used the lens icon from the Material Design Icons from here. After downloading the lens zip I put ic_lens_black_24dp.png under the drawable folder. Then I used the Drawable.setColorFilter() method to change the default color in the code.

I was also able to change the default Marker color, and figured I would include that as well here.

First, set a Renderer by calling setRenderer():

 mClusterManager.setRenderer(new MyClusterRenderer(this, mMap,
                mClusterManager));

Then, define the MyClusterRenderer class:

public class MyClusterRenderer extends DefaultClusterRenderer<MyItem> {

    private final IconGenerator mClusterIconGenerator = new IconGenerator(getApplicationContext());

    public MyClusterRenderer(Context context, GoogleMap map,
                             ClusterManager<MyItem> clusterManager) {
        super(context, map, clusterManager);
    }

    @Override
    protected void onBeforeClusterItemRendered(MyItem item,
                                               MarkerOptions markerOptions) {

        BitmapDescriptor markerDescriptor = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA);

        markerOptions.icon(markerDescriptor);
    }

    @Override
    protected void onClusterItemRendered(MyItem clusterItem, Marker marker) {
        super.onClusterItemRendered(clusterItem, marker);
    }

    @Override
    protected void onBeforeClusterRendered(Cluster<MyItem> cluster, MarkerOptions markerOptions){

        final Drawable clusterIcon = getResources().getDrawable(R.drawable.ic_lens_black_24dp);
        clusterIcon.setColorFilter(getResources().getColor(android.R.color.holo_orange_light), PorterDuff.Mode.SRC_ATOP);

        mClusterIconGenerator.setBackground(clusterIcon);

        //modify padding for one or two digit numbers
        if (cluster.getSize() < 10) {
            mClusterIconGenerator.setContentPadding(40, 20, 0, 0);
        }
        else {
            mClusterIconGenerator.setContentPadding(30, 20, 0, 0);
        }

        Bitmap icon = mClusterIconGenerator.makeIcon(String.valueOf(cluster.getSize()));
        markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon));
    }
}

Full class code:

public class MapsActivity extends AppCompatActivity
        implements ClusterManager.OnClusterItemInfoWindowClickListener<MyItem> {

    private ClusterManager<MyItem> mClusterManager;
    private MyItem clickedClusterItem;
    private GoogleMap mMap;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_maps);

        setUpMapIfNeeded();
    }

    @Override
    protected void onResume() {
        super.onResume();
        setUpMapIfNeeded();
    }


    private void setUpMapIfNeeded() {
        // Do a null check to confirm that we have not already instantiated the map.
        if (mMap == null) {
            // Try to obtain the map from the SupportMapFragment.
            mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map))
                    .getMap();

            // Check if we were successful in obtaining the map.
            if (mMap != null) {
                setUpMap();
            }

        }
    }

    private void setUpMap() {

        mMap.getUiSettings().setMapToolbarEnabled(true);
        mMap.getUiSettings().setZoomControlsEnabled(true);
        mMap.setMyLocationEnabled(true);
        mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);

        mClusterManager = new ClusterManager<>(this, mMap);

        mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(37.779977,-122.413742), 10));

        mMap.setOnCameraChangeListener(mClusterManager);
        mMap.setOnMarkerClickListener(mClusterManager);

        mClusterManager.setRenderer(new MyClusterRenderer(this, mMap,
                mClusterManager));

        mMap.setInfoWindowAdapter(mClusterManager.getMarkerManager());

        mMap.setOnInfoWindowClickListener(mClusterManager); //added
        mClusterManager.setOnClusterItemInfoWindowClickListener(this); //added

        mClusterManager
                .setOnClusterItemClickListener(new ClusterManager.OnClusterItemClickListener<MyItem>() {
                    @Override
                    public boolean onClusterItemClick(MyItem item) {
                        clickedClusterItem = item;
                        return false;
                    }
                });



        addItems();

        mClusterManager.getMarkerCollection().setOnInfoWindowAdapter(
                new MyCustomAdapterForItems());

    }

    private void addItems() {

        double latitude = 37.779977;
        double longitude = -122.413742;
        for (int i = 0; i < 10; i++) {
            double offset = i / 60d;

            double lat = latitude + offset;
            double lng = longitude + offset;
            MyItem offsetItem = new MyItem(lat, lng, "title " + i+1, "snippet " + i+1);
            mClusterManager.addItem(offsetItem);

        }

    }

    //added with edit
    @Override
    public void onClusterItemInfoWindowClick(MyItem myItem) {

        //Cluster item InfoWindow clicked, set title as action
        Intent i = new Intent(this, OtherActivity.class);
        i.setAction(myItem.getTitle());
        startActivity(i);

        //You may want to do different things for each InfoWindow:
        if (myItem.getTitle().equals("some title")){

            //do something specific to this InfoWindow....

        }

    }

    public class MyCustomAdapterForItems implements GoogleMap.InfoWindowAdapter {

        private final View myContentsView;

        MyCustomAdapterForItems() {
            myContentsView = getLayoutInflater().inflate(
                    R.layout.info_window, null);
        }
        @Override
        public View getInfoWindow(Marker marker) {

            TextView tvTitle = ((TextView) myContentsView
                    .findViewById(R.id.txtTitle));
            TextView tvSnippet = ((TextView) myContentsView
                    .findViewById(R.id.txtSnippet));

            tvTitle.setText(clickedClusterItem.getTitle());
            tvSnippet.setText(clickedClusterItem.getSnippet());

            return myContentsView;
        }

        @Override
        public View getInfoContents(Marker marker) {
            return null;
        }
    }

    public class MyClusterRenderer extends DefaultClusterRenderer<MyItem> {

        private final IconGenerator mClusterIconGenerator = new IconGenerator(getApplicationContext());

        public MyClusterRenderer(Context context, GoogleMap map,
                                 ClusterManager<MyItem> clusterManager) {
            super(context, map, clusterManager);
        }

        @Override
        protected void onBeforeClusterItemRendered(MyItem item,
                                                   MarkerOptions markerOptions) {

            BitmapDescriptor markerDescriptor = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA);

            markerOptions.icon(markerDescriptor);
        }

        @Override
        protected void onClusterItemRendered(MyItem clusterItem, Marker marker) {
            super.onClusterItemRendered(clusterItem, marker);
        }

        @Override
        protected void onBeforeClusterRendered(Cluster<MyItem> cluster, MarkerOptions markerOptions){

            final Drawable clusterIcon = getResources().getDrawable(R.drawable.ic_lens_black_24dp);
            clusterIcon.setColorFilter(getResources().getColor(android.R.color.holo_orange_light), PorterDuff.Mode.SRC_ATOP);

            mClusterIconGenerator.setBackground(clusterIcon);

            //modify padding for one or two digit numbers
            if (cluster.getSize() < 10) {
                mClusterIconGenerator.setContentPadding(40, 20, 0, 0);
            }
            else {
                mClusterIconGenerator.setContentPadding(30, 20, 0, 0);
            }

            Bitmap icon = mClusterIconGenerator.makeIcon(String.valueOf(cluster.getSize()));
            markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon));
        }
    }
}

Result:

Initial app launch:

No clustering

Zooming out, some clustering:

initial clustering

Zooming out again, all Markers clustered:

all Markers clustered

like image 107
Daniel Nugent Avatar answered Oct 16 '22 09:10

Daniel Nugent


We can Override getColor in CustomClusterRenderer.

public class CustomClusterRenderer extends DefaultClusterRenderer<CustomClusterItem> {

@Override
    protected int getColor(int clusterSize) {
        return Color.parseColor("#567238");
    }
}
like image 20
Karina Sokolova Avatar answered Oct 16 '22 09:10

Karina Sokolova


I took some methods of superclass and partially remade them. Now i have beautiful standard clusters with my own colors.

public class CustomClusterRenderer extends DefaultClusterRenderer<GoogleMapMarker> {

private final IconGenerator mIconGenerator;
private ShapeDrawable mColoredCircleBackground;
private SparseArray<BitmapDescriptor> mIcons = new SparseArray();
private final float mDensity;
private Context mContext;

public CustomClusterRenderer(Context context, GoogleMap map,
                             ClusterManager<GoogleMapMarker> clusterManager) {
    super(context, map, clusterManager);


    this.mContext = context;
    this.mDensity = context.getResources().getDisplayMetrics().density;
    this.mIconGenerator = new IconGenerator(context);
    this.mIconGenerator.setContentView(this.makeSquareTextView(context));
    this.mIconGenerator.setTextAppearance(
            com.google.maps.android.R.style.ClusterIcon_TextAppearance);
    this.mIconGenerator.setBackground(this.makeClusterBackground());
}

@Override
protected void onBeforeClusterRendered(Cluster<GoogleMapMarker> cluster,
                                       MarkerOptions markerOptions) {
    // Main color
    int clusterColor = mContext.getResources().getColor(R.color.colorPrimary);

    int bucket = this.getBucket(cluster);
    BitmapDescriptor descriptor = this.mIcons.get(bucket);
    if(descriptor == null) {
        this.mColoredCircleBackground.getPaint().setColor(clusterColor);
        descriptor = BitmapDescriptorFactory.fromBitmap(
                this.mIconGenerator.makeIcon(this.getClusterText(bucket)));
        this.mIcons.put(bucket, descriptor);
    }

    markerOptions.icon(descriptor);
}

private SquareTextView makeSquareTextView(Context context) {
    SquareTextView squareTextView = new SquareTextView(context);
    ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(-2, -2);
    squareTextView.setLayoutParams(layoutParams);
    squareTextView.setId(com.google.maps.android.R.id.text);
    int twelveDpi = (int)(12.0F * this.mDensity);
    squareTextView.setPadding(twelveDpi, twelveDpi, twelveDpi, twelveDpi);
    return squareTextView;
}

private LayerDrawable makeClusterBackground() {
    // Outline color
    int clusterOutlineColor = mContext.getResources().getColor(R.color.colorWhite);

    this.mColoredCircleBackground = new ShapeDrawable(new OvalShape());
    ShapeDrawable outline = new ShapeDrawable(new OvalShape());
    outline.getPaint().setColor(clusterOutlineColor);
    LayerDrawable background = new LayerDrawable(
            new Drawable[]{outline, this.mColoredCircleBackground});
    int strokeWidth = (int)(this.mDensity * 3.0F);
    background.setLayerInset(1, strokeWidth, strokeWidth, strokeWidth, strokeWidth);
    return background;
}

And then set renderer to Cluster Manager

mClusterManager = new ClusterManager<>(context, mGoogleMap);
mClusterManager.setRenderer(new CustomClusterRenderer(context, mGoogleMap, mClusterManager));
like image 13
sWift Avatar answered Oct 16 '22 09:10

sWift


Nice custom renderer with centered text and different sizes of clusters:

  public class MyClusterRenderer extends DefaultClusterRenderer<Station> {

    private final IconGenerator mClusterIconGeneratorBig = new IconGenerator(getCtx());
    private final IconGenerator mClusterIconGeneratorMed = new IconGenerator(getCtx());
    private final IconGenerator mClusterIconGeneratorSml = new IconGenerator(getCtx());
    final Drawable clusterIconBig = getResources().getDrawable(R.drawable.marker1);
    final Drawable clusterIconMed = getResources().getDrawable(R.drawable.marker2);
    final Drawable clusterIconSml = getResources().getDrawable(R.drawable.marker3);

    public MyClusterRenderer(Context context, GoogleMap map,
                             ClusterManager<Station> clusterManager) {
        super(context, map, clusterManager);
        setupIconGen(mClusterIconGeneratorBig, clusterIconBig, context);
        setupIconGen(mClusterIconGeneratorMed, clusterIconMed, context);
        setupIconGen(mClusterIconGeneratorSml, clusterIconSml, context);
    }

    private void setupIconGen(IconGenerator generator, Drawable drawable, Context context) {
        TextView textView = new TextView(context);
        textView.setTextAppearance(context, R.style.BubbleText);
        textView.setTypeface(App.FONTS[2]);
        textView.setId(com.google.maps.android.R.id.amu_text);
        textView.setGravity(android.view.Gravity.CENTER);
        textView.setLayoutParams(new FrameLayout.LayoutParams(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()));
        generator.setContentView(textView);
        generator.setBackground(drawable);
    }

    @Override
    protected void onBeforeClusterItemRendered(Station item, MarkerOptions markerOptions) {
        BitmapDescriptor markerDescriptor = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA);
        markerOptions.icon(markerDescriptor);
    }

    @Override
    protected void onClusterItemRendered(Station clusterItem, Marker marker) {
        super.onClusterItemRendered(clusterItem, marker);
    }

    @Override
    protected void onBeforeClusterRendered(Cluster<Station> cluster, MarkerOptions markerOptions) {
        if (cluster.getSize() > 20) {
            Bitmap icon = mClusterIconGeneratorBig.makeIcon(String.valueOf(cluster.getSize()));
            markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon));
        } else if (cluster.getSize() > 10) {
            Bitmap icon = mClusterIconGeneratorMed.makeIcon(String.valueOf(cluster.getSize()));
            markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon));
        } else {
            Bitmap icon = mClusterIconGeneratorSml.makeIcon(String.valueOf(cluster.getSize()));
            markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon));
        }
    }

    @Override
    protected boolean shouldRenderAsCluster(Cluster cluster) {
        return cluster.getSize() > 5;
    }
}

enter image description here

like image 6
Hox Avatar answered Oct 16 '22 09:10

Hox