I try to cluster some points in my application map, It work prefect for first time and data clustered but when try to update the list again with new data not change happen and clusters still exist I try to use clearItems(), clear() map but no change happen the following is my code for it can any one help please.
Code for map
((SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.map)).getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(final GoogleMap googleMap) {
mMap = googleMap;
LatLngBounds ADELAIDE = new LatLngBounds(
new LatLng(16.57946, 35.69014), new LatLng(31.67252, 50.20833));
mMap.setLatLngBoundsForCameraTarget(ADELAIDE);
final LatLng location = new LatLng(mDefaultLat, mDefaultLng);
mClusterManager = new ClusterManager<>(getContext(), mMap);
mClusterManager.setRenderer(new ClusterRenderer(getContext(), mMap, mClusterManager));
final CameraPosition[] mPreviousCameraPosition = {null};
mMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() {
#Override
public void onCameraIdle() {
CameraPosition position = googleMap.getCameraPosition();
mDefaultLat = position.target.latitude;
mDefaultLng = position.target.longitude;
locationFromMap = true;
populate();
if (mPreviousCameraPosition[0] == null || mPreviousCameraPosition[0].zoom != position.zoom) {
mPreviousCameraPosition[0] = googleMap.getCameraPosition();
addItems();
}
}
});
mMap.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() {
#Override
public void onMapLoaded() {
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(location, 16));
}
});
mMap.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
#Override
public boolean onMarkerClick(Marker marker) {
try {
new OfficeDialog(mActivity, officeList.get(Integer.parseInt(marker.getSnippet()))).show();
} catch (Exception e) {
}
return true;
}
});
}
});
addItems function
private void addItems() {
if (!listAdded && officeList.size() > 0) {
mClusterManager.clearItems();
mClusterManager.cluster();
mClusterManager.addItems(officeList);
listAdded = true;
}
mClusterManager.cluster();
}
and my cluster manager custom render
public class ClusterRenderer extends DefaultClusterRenderer<Office> {
Context context;
private IconGenerator iconGenerator;
private float density;
public ClusterRenderer(Context context, GoogleMap map, ClusterManager<Office> clusterManager) {
super(context, map, clusterManager);
clusterManager.setRenderer(this);
this.context = context;
density = context.getResources().getDisplayMetrics().density;
}
#Override
protected void onBeforeClusterItemRendered(Office item, MarkerOptions markerOptions) {
markerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.ejar_location_icon_copy));
}
#Override
protected void onBeforeClusterRendered(Cluster<Office> cluster, MarkerOptions markerOptions) {
if(iconGenerator == null) {
iconGenerator = new IconGenerator(context);
iconGenerator.setContentView(makeTextView(context));
}
iconGenerator.setBackground(makeBackground(false, cluster.getSize()));
markerOptions.icon(BitmapDescriptorFactory.fromBitmap(iconGenerator.makeIcon(String.valueOf(cluster.getSize()))));
}
#Override
protected void onClusterRendered(Cluster<Office> cluster, Marker marker) {
super.onClusterRendered(cluster, marker);
}
#Override
protected boolean shouldRenderAsCluster(Cluster<Office> cluster) {
return cluster.getSize() > 1;
}
private ShapeDrawable makeBackground(boolean isClicked, int size) {
ShapeDrawable background = new ShapeDrawable(new OvalShape());
int color = ContextCompat.getColor(context, R.color.colorPrimary);
if (size < 50) {
color = ContextCompat.getColor(context, R.color.colorPrimary);
} else if (size < 100) {
color = ContextCompat.getColor(context, R.color.cluster_50);
} else if (size < 200) {
color = ContextCompat.getColor(context, R.color.cluster_100);
} else if (size < 1000) {
color = ContextCompat.getColor(context, R.color.cluster_200);
} else color = ContextCompat.getColor(context, R.color.cluster_1000);
background.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
return background;
}
private SquareTextView makeTextView(Context context) {
SquareTextView squareTextView = new SquareTextView(context);
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(-2, -2);
squareTextView.setLayoutParams(layoutParams);
squareTextView.setTextColor(ContextCompat.getColor(context, R.color.white));
squareTextView.setId(com.google.maps.android.R.id.text);
int twelveDpi = (int) (12.0F * density);
squareTextView.setPadding(twelveDpi, twelveDpi, twelveDpi, twelveDpi);
return squareTextView;
}
public IconGenerator getIconGenerator(boolean isClicked) {
iconGenerator.setBackground(makeBackground(isClicked, 0));
return iconGenerator;
}
}
After debug and search about this issue I didn't found any reason about it so after check my web service I found the issue on it.
Web service return static locations for my objects so the clusters not changed after fix it the application works correctly without any issues.
Related
can i add a Map style with a marker cluster in android? because i try with this line:
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
MapStyleOptions style = loadRawResourceStyle(Mapa.this, R.raw.estilo_map);
mMap.setMapStyle(style);
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(-33.502482, -70.573841), 8));
mMap.getUiSettings().setMapToolbarEnabled(false);
mMap.getUiSettings().setMyLocationButtonEnabled(true);
mMap.getUiSettings().setZoomControlsEnabled(false);
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
mMap.setMyLocationEnabled(true);
mMap.setMinZoomPreference(10);
mMap.setMaxZoomPreference(20);
mMap.setLatLngBoundsForCameraTarget(new LatLngBounds(new LatLng(-33.660048, -70.801025),new LatLng(-33.271212, -70.471835)));
mClusterManager = new ClusterManager<>(Mapa.this, mMap);
RenderClusterInfoWindow renderer = new RenderClusterInfoWindow(Mapa.this, mMap, mClusterManager);
mClusterManager.setRenderer(renderer);
mMap.setOnCameraIdleListener(mClusterManager);
mMap.setOnMarkerClickListener(mClusterManager);
mMap.setOnInfoWindowClickListener(mClusterManager);
clusterMarcadores();
mClusterManager.setOnClusterItemClickListener(new ClusterManager.OnClusterItemClickListener<FormatoMarcadores>() {
#Override
public boolean onClusterItemClick(FormatoMarcadores formatoMarcadores) {//abrir valorar y reportar aqui
Log.d("ciclovia", formatoMarcadores.getTitle());
d.ruta(formatoMarcadores.getTitle(), mMap);
markerClick(formatoMarcadores.getTitle(),formatoMarcadores.getPosition());
return false;
}
});
mClusterManager.setOnClusterClickListener(new ClusterManager.OnClusterClickListener<FormatoMarcadores>() {
#Override
public boolean onClusterClick(Cluster<FormatoMarcadores> cluster) {
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(cluster.getPosition(), (float) Math.floor(mMap.getCameraPosition().zoom + 2)));
return true;
}
});
mClusterManager.cluster();
mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
#Override
public void onMapClick(LatLng latLng) {
d.quitarPolyline();
if (bottomSheet.isHideable()){
bottomSheet.setState(BottomSheetBehavior.STATE_HIDDEN);
}
}
});
}
and i have this: link to picture
maps works perfectly without style, and if i use the mMap.setMapStyle(style); as boolean, i get the style is applied correctly
Create you map theme from here
Download your style.json -> copy in raw resorce file
mGoogleMap.setMapStyle(
MapStyleOptions.loadRawResourceStyle(
this, R.raw.style_json));
try this code:
public class CustomMarkerClusteringDemoActivity extends BaseDemoActivity implements ClusterManager.OnClusterClickListener<Person>, ClusterManager.OnClusterInfoWindowClickListener<Person>, ClusterManager.OnClusterItemClickListener<Person>, ClusterManager.OnClusterItemInfoWindowClickListener<Person> {
private ClusterManager<Person> mClusterManager;
private Random mRandom = new Random(1984);
/**
* Draws profile photos inside markers (using IconGenerator).
* When there are multiple people in the cluster, draw multiple photos (using MultiDrawable).
*/
private class PersonRenderer extends DefaultClusterRenderer<Person> {
private final IconGenerator mIconGenerator = new IconGenerator(getApplicationContext());
private final IconGenerator mClusterIconGenerator = new IconGenerator(getApplicationContext());
private final ImageView mImageView;
private final ImageView mClusterImageView;
private final int mDimension;
public PersonRenderer() {
super(getApplicationContext(), getMap(), mClusterManager);
View multiProfile = getLayoutInflater().inflate(R.layout.multi_profile, null);
mClusterIconGenerator.setContentView(multiProfile);
mClusterImageView = (ImageView) multiProfile.findViewById(R.id.image);
mImageView = new ImageView(getApplicationContext());
mDimension = (int) getResources().getDimension(R.dimen.custom_profile_image);
mImageView.setLayoutParams(new ViewGroup.LayoutParams(mDimension, mDimension));
int padding = (int) getResources().getDimension(R.dimen.custom_profile_padding);
mImageView.setPadding(padding, padding, padding, padding);
mIconGenerator.setContentView(mImageView);
}
#Override
protected void onBeforeClusterItemRendered(Person person, MarkerOptions markerOptions) {
// Draw a single person.
// Set the info window to show their name.
mImageView.setImageResource(person.profilePhoto);
Bitmap icon = mIconGenerator.makeIcon();
markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon)).title(person.name);
}
#Override
protected void onBeforeClusterRendered(Cluster<Person> cluster, MarkerOptions markerOptions) {
// Draw multiple people.
// Note: this method runs on the UI thread. Don't spend too much time in here (like in this example).
List<Drawable> profilePhotos = new ArrayList<Drawable>(Math.min(4, cluster.getSize()));
int width = mDimension;
int height = mDimension;
for (Person p : cluster.getItems()) {
// Draw 4 at most.
if (profilePhotos.size() == 4) break;
Drawable drawable = getResources().getDrawable(p.profilePhoto);
drawable.setBounds(0, 0, width, height);
profilePhotos.add(drawable);
}
MultiDrawable multiDrawable = new MultiDrawable(profilePhotos);
multiDrawable.setBounds(0, 0, width, height);
mClusterImageView.setImageDrawable(multiDrawable);
Bitmap icon = mClusterIconGenerator.makeIcon(String.valueOf(cluster.getSize()));
markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon));
}
#Override
protected boolean shouldRenderAsCluster(Cluster cluster) {
// Always render clusters.
return cluster.getSize() > 1;
}
}
#Override
public boolean onClusterClick(Cluster<Person> cluster) {
// Show a toast with some info when the cluster is clicked.
String firstName = cluster.getItems().iterator().next().name;
Toast.makeText(this, cluster.getSize() + " (including " + firstName + ")", Toast.LENGTH_SHORT).show();
// Zoom in the cluster. Need to create LatLngBounds and including all the cluster items
// inside of bounds, then animate to center of the bounds.
// Create the builder to collect all essential cluster items for the bounds.
LatLngBounds.Builder builder = LatLngBounds.builder();
for (ClusterItem item : cluster.getItems()) {
builder.include(item.getPosition());
}
// Get the LatLngBounds
final LatLngBounds bounds = builder.build();
// Animate camera to the bounds
try {
getMap().animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 100));
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
#Override
public void onClusterInfoWindowClick(Cluster<Person> cluster) {
// Does nothing, but you could go to a list of the users.
}
#Override
public boolean onClusterItemClick(Person item) {
// Does nothing, but you could go into the user's profile page, for example.
return false;
}
#Override
public void onClusterItemInfoWindowClick(Person item) {
// Does nothing, but you could go into the user's profile page, for example.
}
#Override
protected void startDemo() {
getMap().moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(51.503186, -0.126446), 9.5f));
mClusterManager = new ClusterManager<Person>(this, getMap());
mClusterManager.setRenderer(new PersonRenderer());
getMap().setOnCameraIdleListener(mClusterManager);
getMap().setOnMarkerClickListener(mClusterManager);
getMap().setOnInfoWindowClickListener(mClusterManager);
mClusterManager.setOnClusterClickListener(this);
mClusterManager.setOnClusterInfoWindowClickListener(this);
mClusterManager.setOnClusterItemClickListener(this);
mClusterManager.setOnClusterItemInfoWindowClickListener(this);
addItems();
mClusterManager.cluster();
}
private void addItems() {
// http://www.flickr.com/photos/sdasmarchives/5036248203/
mClusterManager.addItem(new Person(position(), "Walter", R.drawable.walter));
// http://www.flickr.com/photos/usnationalarchives/4726917149/
mClusterManager.addItem(new Person(position(), "Gran", R.drawable.gran));
// http://www.flickr.com/photos/nypl/3111525394/
mClusterManager.addItem(new Person(position(), "Ruth", R.drawable.ruth));
// http://www.flickr.com/photos/smithsonian/2887433330/
mClusterManager.addItem(new Person(position(), "Stefan", R.drawable.stefan));
// http://www.flickr.com/photos/library_of_congress/2179915182/
mClusterManager.addItem(new Person(position(), "Mechanic", R.drawable.mechanic));
// http://www.flickr.com/photos/nationalmediamuseum/7893552556/
mClusterManager.addItem(new Person(position(), "Yeats", R.drawable.yeats));
// http://www.flickr.com/photos/sdasmarchives/5036231225/
mClusterManager.addItem(new Person(position(), "John", R.drawable.john));
// http://www.flickr.com/photos/anmm_thecommons/7694202096/
mClusterManager.addItem(new Person(position(), "Trevor the Turtle", R.drawable.turtle));
// http://www.flickr.com/photos/usnationalarchives/4726892651/
mClusterManager.addItem(new Person(position(), "Teach", R.drawable.teacher));
}
private LatLng position() {
return new LatLng(random(51.6723432, 51.38494009999999), random(0.148271, -0.3514683));
}
private double random(double min, double max) {
return mRandom.nextDouble() * (max - min) + min;
}
}
please check my code it is working fine i think it helps you.
I want to change the background of the cluster marker on click. I do this via
#Override
onClusterClick(Cluster<MyObject> cluster) {
Marker marker = renderer.getMarker(cluster);
marker.setIcon(....);
}
This works fine expect for one case: When I zoom in or out and the number of cluster markers doesn't change. For example, if I had a 15 cluster and a 5 cluster, then zoom a level in or out, the same two clusters remain. Clicking on one of these now renderer.getMarker(cluster) returns null. If they re-cluster after zooming, getMarker is not null.
My DefaultClusterRenderer is below. I checked the marker on onClusteredRendered and it's never null. Is this a bug in the DefaultClusterRenderer or should I do something else?
private class MyRenderer extends DefaultClusterRenderer<MyObject> {
private IconGenerator iconGenerator;
private float density;
public MyRenderer(Context context, GoogleMap map, ClusterManager<MyObject> clusterManager) {
super(context, map, clusterManager);
density = context.getResources().getDisplayMetrics().density;
}
#Override
protected void onBeforeClusterItemRendered(MyObject item, MarkerOptions markerOptions) {
markerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.my_pin));
}
#Override
protected void onBeforeClusterRendered(Cluster<MyObject> cluster, MarkerOptions markerOptions) {
if(iconGenerator == null) {
iconGenerator = new IconGenerator(getActivity());
iconGenerator.setContentView(makeTextView(getActivity()));
}
iconGenerator.setBackground(makeBackground(false));
markerOptions.icon(BitmapDescriptorFactory.fromBitmap(iconGenerator.makeIcon(String.valueOf(cluster.getSize()))));
}
#Override
protected void onClusterRendered(Cluster<MyObject> cluster, Marker marker) {
super.onClusterRendered(cluster, marker);
// Marker is never null here
}
#Override
protected boolean shouldRenderAsCluster(Cluster<MyObject> cluster) {
return cluster.getSize() > 1;
}
private ShapeDrawable makeBackground(boolean isClicked) {
ShapeDrawable background = new ShapeDrawable(new OvalShape());
background.setColorFilter(ContextCompat.getColor(getActivity(),
isClicked ? R.color.cluster_marker_clicked : R.color.cluster_marker_unclicked), PorterDuff.Mode.SRC_ATOP);
return background;
}
private SquareTextView makeTextView(Context context) {
SquareTextView squareTextView = new SquareTextView(context);
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(-2, -2);
squareTextView.setLayoutParams(layoutParams);
squareTextView.setTextColor(ContextCompat.getColor(getActivity(), R.color.white));
squareTextView.setTypeface(Utils.getFontBold(getActivity()));
squareTextView.setId(com.google.maps.android.R.id.text);
int twelveDpi = (int) (12.0F * density);
squareTextView.setPadding(twelveDpi, twelveDpi, twelveDpi, twelveDpi);
return squareTextView;
}
public IconGenerator getIconGenerator(boolean isClicked) {
iconGenerator.setBackground(makeBackground(isClicked));
return iconGenerator;
}
}
Initializing the ClusterManager:
final ClusterManager<MyObject> mClusterManager = new ClusterManager<>(getActivity(), googleMap);
mClusterManager.addItems(items);
renderer = new CustomRenderer(getActivity(), googleMap, mClusterManager);
mClusterManager.setRenderer(renderer);
mClusterManager.cluster();
mClusterManager.setOnClusterItemClickListener(this);
googleMap.setOnMarkerClickListener(mClusterManager);
#antonio: This initialization is working for me:
public class MapsActivity extends FragmentActivity
implements ClusterManager.OnClusterClickListener<MyObject> {
// ...
private void setUpClusterer() {
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(51.503186, -0.126446), 10));
mClusterManager = new ClusterManager<MyObject>(this, googleMap);
mClusterManager.setOnClusterClickListener(this);
renderer = new MyRenderer(this, googleMap, mClusterManager);
mClusterManager.setRenderer(renderer);
googleMap.setOnCameraChangeListener(mClusterManager);
googleMap.setOnMarkerClickListener(mClusterManager);
addItems();
}
private void addItems() {
// Set some lat/lng coordinates to start with.
double lat = 51.5145160;
double lng = -0.1270060;
// Add ten cluster items in close proximity, for purposes of this example.
for (int i = 0; i < 10; i++) {
double offset = i / 60d;
lat = lat + offset;
lng = lng + offset;
MyObject offsetItem = new MyObject(lat, lng);
mClusterManager.addItem(offsetItem);
}
}
#Override
public boolean onClusterClick(final Cluster<MyObject> cluster) {
Marker marker = renderer.getMarker(cluster);
marker.setIcon(BitmapDescriptorFactory.fromResource(R.drawable.my_newpin));
return true;
}
}
Couldn't get renderer.getMarker(cluster) to return a marker in that case above. A work around was to create:
Map <Cluster<MyObject>, Marker> clusterMarkerMap = new HashMap<>();
then add them on the DefaultClusterRenderer callback because the marker is never null there:
#Override
protected void onClusterRendered(Cluster<MyObject> cluster, Marker marker) {
super.onClusterRendered(cluster, marker);
clusterMarkerMap.put(cluster, marker);
}
Because the DefaultClusterManager clears them when the camera position changes, wipe the cluster marker map before it creates new ones:
googleMap.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() {
#Override
public void onCameraChange(CameraPosition cameraPosition) {
// Clear the map here because the markers will be recreated
// when the manager is notified of a (zoom level) camera change
if(zoomLevelChanged)
clusterMarkerMap.clear();
mClusterManager.onCameraChange(cameraPosition);
}
});
Now I can get the marker successfully clusterMarkerMap.get(cluster)
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.
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");
}
}
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));
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;
}
}
Go to DefaultClusterRenderer (package com.google.maps.android.clustering.view;), and change the getColor() method to this:
private int getColor(int clusterSize) {
// custom color
double _logClusterSize; // log
final int _maxRed = Integer.parseInt("ff", 16);
// Log.v("kai", String.valueOf(_maxRed));
final int _minRed = Integer.parseInt("e6", 16);
final int _maxGreen = Integer.parseInt("a2", 16);
final int _minGreen = Integer.parseInt("47", 16);
final int _maxBlue = Integer.parseInt("93", 16);
final int _minBlue = Integer.parseInt("2d", 16);
final double _maxLogClusterSize = 10;
double _step = (_maxRed - _minRed) / _maxLogClusterSize;
_logClusterSize = Math.log(clusterSize);
if(_logClusterSize > 10) _logClusterSize = 10;
int _red = _maxRed - (int) (_step * _logClusterSize);
int _green = _maxGreen - (int) (_step * _logClusterSize);
int _blue = _maxBlue - (int) (_step * _logClusterSize);
return Color.rgb(_red, _green, _blue);
// 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
// });
}
This will change the Cluster color to pink, in the range of the color defined by min(max) red(green, blue). Hope that help!
Sadly, overriding getColor doesn't work for me. But this looks enough to change the marker color (and something else):
class ClusterItemRenderer(
context: Context, map: GoogleMap,
clusterManager: ClusterManager<ClusterMarker>
) : DefaultClusterRenderer<ClusterMarker>(context, map, clusterManager) {
override fun onBeforeClusterItemRendered(item: ClusterMarker, markerOptions: MarkerOptions) {
val markerDescriptor = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA)
markerOptions.icon(markerDescriptor)
}
}
It's also possible to add updates according to the recommendations:
If you're using custom clustering (i.e, if you're extending
DefaultClusterRenderer), you must override two additional methods in
v1:
onClusterItemUpdated() - should be the same* as your onBeforeClusterItemRendered() method
onClusterUpdated() - should be the same* as your onBeforeClusterRendered() method
*Note that these methods can't be identical, as you need to use a Marker instead of MarkerOptions
override fun onClusterItemUpdated(item: ClusterMarker, marker: Marker) {
val markerDescriptor = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA)
marker.setIcon(markerDescriptor)
}
I want to add an info window on top of Each marker set when user tap on a marker. Here is my code. The marker is fine i need only the infowindow appears on top of it. how can i achieve this, here is my code
public class MainActivity extends MapActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
MapView mapView = (MapView) findViewById(R.id.mapview);
mapView.setBuiltInZoomControls(true);
mapView.setSatellite(true);
Drawable makerDefault = this.getResources().getDrawable(R.drawable.marker_default);
MyItemizedOverlay itemizedOverlay = new MyItemizedOverlay(makerDefault);
Drawable windmill = getResources().getDrawable(R.drawable.windmill);
Drawable bigBen = getResources().getDrawable(R.drawable.big_ben);
Drawable eiffelTower = getResources().getDrawable(R.drawable.eiffel_tower);
itemizedOverlay.addOverlayItem(52372991, 4892655, "Amsterdam", windmill);
itemizedOverlay.addOverlayItem(51501851, -140623, "London", bigBen);
itemizedOverlay.addOverlayItem(48857522, 2294496, "Paris", eiffelTower);
mapView.getOverlays().add(itemizedOverlay);
MapController mc = mapView.getController();
mc.setCenter(new GeoPoint(51035349, 2370987)); // Dunkerque, Belgium
mc.zoomToSpan(itemizedOverlay.getLatSpanE6(), itemizedOverlay.getLonSpanE6());
}
#Override
protected boolean isRouteDisplayed() {
return false;
}
private class MyItemizedOverlay extends ItemizedOverlay<OverlayItem> {
private List<OverlayItem> mOverlays = new ArrayList<OverlayItem>();
public MyItemizedOverlay(Drawable defaultMarker) {
super(boundCenterBottom(defaultMarker));
}
public void addOverlayItem(int lat, int lon, String title, Drawable altMarker) {
GeoPoint point = new GeoPoint(lat, lon);
OverlayItem overlayItem = new OverlayItem(point, title, null);
addOverlayItem(overlayItem, altMarker);
}
public void addOverlayItem(OverlayItem overlayItem) {
mOverlays.add(overlayItem);
populate();
}
public void addOverlayItem(OverlayItem overlayItem, Drawable altMarker) {
overlayItem.setMarker(boundCenterBottom(altMarker));
addOverlayItem(overlayItem);
}
#Override
protected OverlayItem createItem(int i) {
return mOverlays.get(i);
}
#Override
public int size() {
return mOverlays.size();
}
#Override
protected boolean onTap(int index) {
Toast.makeText(MainActivity.this, getItem(index).getTitle(), Toast.LENGTH_LONG).show();
return true;
}
}
}
SitesOverlay.class
private class SitesOverlay extends ItemizedOverlay<CustomItem> {
private List<CustomItem> items;
private View view = null;
public SitesOverlay() {
super(null);
items = new ArrayList<CustomItem>();
items.add(new CustomItem(pt, busName, "Bendigo", marker));
boundCenter(marker);
populate();
}
#Override
protected CustomItem createItem(int i) {
return (items.get(i));
}
#Override
public void draw(Canvas canvas, MapView mapView, boolean shadow) {
if (!shadow) {
super.draw(canvas, mapView, false);
}
}
#Override
public int size() {
return (items.size());
}
public void refresh() {
populate();
}
public void clear() {
items.clear();
resetLastFocuesIndex();
}
public void resetLastFocuesIndex() {
setLastFocusedIndex(-1);
}
#Override
protected boolean onTap(final int index) {
if (view != null) {
view.setVisibility(View.GONE);
getMapView().removeView(view);
getMapView().invalidate();
view = null;
}
view = getLayoutInflater().inflate(R.layout.balloon_overlay, null);
LinearLayout layout = (LinearLayout) view
.findViewById(R.id.balloon_main_layout);
layout.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
view.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
view.setBackgroundResource(R.drawable.balloon_overlay_bg_selector);
ImageView image = (ImageView) view
.findViewById(R.id.balloon_disclosure);
TextView text = (TextView) view
.findViewById(R.id.balloon_item_title);
text.setText(items.get(index).getTitle());
Projection projection = getMapView().getProjection();
Point point = new Point();
projection.toPixels(items.get(index).getPoint(), point);
int x = (int) (view.getWidth() / 2f);
int y = -marker.getIntrinsicHeight() - 3;
MapView.LayoutParams lp = new MapView.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT, items.get(index)
.getPoint(), x, y + 50,
MapView.LayoutParams.BOTTOM_CENTER);
getMapView().removeView(view);
getMapView().invalidate();
getMapView().addView(view, lp);
getMapView().invalidate();
view.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
if (!items.isEmpty()) {
if (view != null) {
view.setVisibility(View.GONE);
getMapView().invalidate();
// Intent intent=new Intent(MapLocationActivity.this,);
}
}
getMapView().invalidate();
}
});
return true;
}
}
class CustomItem extends OverlayItem {
Drawable marker = null;
CustomItem(GeoPoint pt, String name, String snippet, Drawable marker) {
super(pt, name, snippet);
this.marker = marker;
}
#Override
public Drawable getMarker(int stateBitset) {
Drawable result = marker;
setState(result, stateBitset);
return (result);
}
}
set Overlay mapview.getOverlays().add(new SitesOverlay());
if there is multiple marker then
for (int i = 0; i < arrayList.size(); i++) {
slat = Double.parseDouble(arrayList.get(i).getLat());
vlong = Double.parseDouble(arrayList.get(i).getvLong());
pt = new GeoPoint((int) (slat * 1E6), (int) (vlong * 1E6));
Log.e("lat long", "--- "+slat);
MapviewActivity.this.mc.animateTo(pt);
items.add(new CustomItem(pt, arrayList.get(i).getBuissnessName(), "Bendigo", marker));
boundCenter(marker);
}
There is already an overlay, drawing something on a map view. I want to add another overlay and a customized item to the map view. Nothing shows. What's wrong with my code? Thanks heaps.
My sub-class of ItemizedOverlay
public class PinItemizedOverlay extends ItemizedOverlay {
private static int MAX_PIN = 3;
private OverlayItem overlays[] = new OverlayItem[MAX_PIN];
private int index = 0;
private boolean full = false;
private Context context;
public PinItemizedOverlay(Context context, Drawable defaultMarker) {
//super(boundCenterBottom(defaultMarker));
super(boundCenterBottom(defaultMarker));
this.context = context;
}
#Override
public OverlayItem createItem(int index) {
return overlays[index];
}
public int size(){
if (full) {
return overlays.length;
} else {
return index;
}
}
public void addOverlay(OverlayItem overlay) {
if (index < MAX_PIN) {
overlays[index] = overlay;
} else {
return;
}
index++;
populate();
}
}
My customized overlay item
public class LocationPinItem extends OverlayItem{
public LocationEntity location;
public LocationPinItem(GeoPoint point, int iconRes, LocationEntity location){
//super(point,null,null);
super(point, null, null);
Drawable marker = getApplicationContext().getResources().getDrawable(iconRes);
super.setMarker(marker );
this.location = location;
}
}
And the function where I add the customized item (it's a drop pin):
private void createMarkerAt(LocationEntity location, String extra, int iconRes, boolean clear, boolean animate) {
if(location == null) {
return;
}
GeoPoint point = new GeoPoint((int) (location.latitude * 1E6), (int) (location.longitude * 1E6));
LocationPinItem pinItem = new LocationPinItem(point,R.drawable.ic_swap,location);
PinItemizedOverlay pinOverlay = new PinItemizedOverlay(getApplicationContext(),mMapDrawable) ;
pinOverlay.addOverlay(pinItem);
mMapView.removeAllViews();
mMapView.postInvalidate();
mMapView.getOverlays().add(pinOverlay);
if(animate) {
mMapView.getController().animateTo(location.toGeoPoint());
}
}
never mind, I figured it out: the newly-added overlay occludes the previous overlay