Android maps utils cluster icon color
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:
Zooming out, some clustering:
Zooming out again, all Markers clustered:
We can Override getColor in CustomClusterRenderer.
public class CustomClusterRenderer extends DefaultClusterRenderer<CustomClusterItem> {
@Override
protected int getColor(int clusterSize) {
return Color.parseColor("#567238");
}
}
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;
}
}
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));