I'm trying to implement clusters for my googlemaps markers. Currently I have some custom marker colors with an API call that fires when you click on them. When those results are loaded, there will open a bottomsheet with the specific information of that marker.
I want to keep the same functionalities (custom markers/clickListeners/radius around markers), but add clusters when zoomed out. I've looked at different sources for help:
Android cluster and marker clicks
But i'm not sure how to implement the custom marker and listener for the clusters items. I'am able to get clusters with standard markers without clicklisteners. Here are some images for illustration:
This is my current situation (I want to cluster these markers). As you can see, the bottom sheet pops up when I click on a marker
This is what I'm currently able to do, but I want to combine it with the previous picture
Here is the important part of my code of my map Fragment, (The Point
class does implement the ClusterItem
interface):
private Map<Marker, Point> retailerInfo = new HashMap<>();
private void markGeofencesOnMap() {
new GeofenceAreasRequest().getAllAreas(new GeofenceAreasCallback() {
@Override
public void onAreasLoaded(List<Point> points) {
for (final Point point : points) {
markerForGeofence(point);
drawRadius(point);
}
}
@Override
public void failedOnAreasLoaded(int message) {
Snackbar.make(coordinatorLayout, R.string.failed_loading_areas, Snackbar.LENGTH_LONG).show();
}
});
}
private void markerForGeofence(Point point) {
LatLng latLng = new LatLng(point.getLatitude(), point.getLongitude());
MarkerOptions markerOptions = new MarkerOptions()
.position(latLng)
.flat(true)
.title(point.getTitle())
.icon(BitmapDescriptorFactory.defaultMarker(195));
// markerManager.getCollection("markerCollection").addMarker(markerOptions);
// markerManager.getCollection("markerCollection").setOnMarkerClickListener(this);
// mClusterManager.addItem(point);
geoFenceMarker = googleMap.addMarker(markerOptions);
retailerInfo.put(geoFenceMarker, point);
}
private void drawRadius(Point point) {
CircleOptions circleOptions = new CircleOptions()
.center(geoFenceMarker.getPosition())
.strokeColor(Color.argb(50, 70, 70, 70))
.fillColor(Color.argb(100, 150, 150, 150))
.radius(point.getRadius());
googleMap.addCircle(circleOptions);
}
private void googleMapSettings() {
int permissionCheck = ContextCompat.checkSelfPermission(getActivity(),
Manifest.permission.ACCESS_FINE_LOCATION);
if (permissionCheck == PackageManager.PERMISSION_GRANTED) {
googleMap.setMyLocationEnabled(true);
} else {
SystemRequirementsChecker.checkWithDefaultDialogs(getActivity());
}
googleMap.getUiSettings().setZoomControlsEnabled(true);
CameraPosition cameraPosition = new CameraPosition.Builder().target(getLastLocation()).zoom(12).build();
googleMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
googleMap.setOnMapClickListener(this);
// markerManager = new MarkerManager(googleMap);
// markerManager.newCollection("markerCollection");
// mClusterManager = new ClusterManager<Point>(getActivity(), googleMap );//, markerManager);
// googleMap.setOnMarkerClickListener(mClusterManager); //markerManager);
googleMap.setOnCameraIdleListener(mClusterManager);
googleMap.setOnMarkerClickListener(this);
}
@Override
public boolean onMarkerClick(Marker marker) {
if (retailerInfo != null) {
String retailerId = retailerInfo.get(marker).getRetailer();
new RetailersRequest().getRetailer(retailerId, new RetailersCallback() {
@Override
public void onRetailersLoad(List<Retailer> retailers) {
for (final Retailer retailer : retailers) {
mMapRetailerName.setText(retailer.getName());
mMapRetailerStreet.setText(retailer.getStreet());
mMapRetailerHouseNr.setText(retailer.getHousenumber());
mMapRetailerPostalCode.setText(retailer.getPostalCode());
mMapRetailerCity.setText(retailer.getCity());
}
bottomSheet.setVisibility(View.VISIBLE);
mBottomSheetBehavior.setPeekHeight(400);
mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
}
@Override
public void failedOnRetailersLoaded(int code) {
Snackbar.make(coordinatorLayout, getString(R.string.failed_loading_retailers) + code, Snackbar.LENGTH_LONG).show();
}
});
CameraPosition cameraPosition = new CameraPosition.Builder().target(marker.getPosition()).zoom(14).build();
googleMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
}
return true;
}
@Override
public void onMapClick(LatLng latLng) {
bottomSheet.setVisibility(View.GONE);
}
@Override
public void onMapReady(GoogleMap googleMap) {
this.googleMap = googleMap;
googleMapSettings();
markGeofencesOnMap();
}
I hope someone can help me out in the right direction. Thx!
Okay, after some more trail and error, I think I've got it sorted out for the most part. All I had to do was to attach a custom DefaultClusterRenderer
to my clusterManager. In the mapfragment I could use onClusterItemClick
for handling the marker clicks. The one problem I still have is that the circles are not all properly rendered when zooming in and out.
private void markGeofencesOnMap() {
new GeofenceAreasRequest().getAllAreas(new GeofenceAreasCallback() {
@Override
public void onAreasLoaded(List<Point> points) {
for (final Point point : points) {
mClusterManager.addItem(point);
}
}
});
}
private void googleMapSettings() {
mClusterManager = new ClusterManager<Point>(getActivity(), googleMap );
// attach custom renderer behaviour
mClusterManager.setRenderer(new OwnPointRendered(getActivity().getApplicationContext(), googleMap, mClusterManager));
mClusterManager.setOnClusterItemClickListener(this);
googleMap.setOnMarkerClickListener(mClusterManager);
googleMap.setOnCameraIdleListener(mClusterManager);
}
@Override
public boolean onClusterItemClick(ClusterItem clusterItem) {
// cast ClusterItem to my Point class to handle marker clicks
Point retailer = (Point) clusterItem;
String retailerId = retailer.getRetailer();
return true;
}
OwnPointRendered.class
public class OwnPointRendered extends DefaultClusterRenderer<Point> {
private final GoogleMap map;
private List<Circle> circleList = new ArrayList<>();
public OwnPointRendered(Context context, GoogleMap map,
ClusterManager<Point> clusterManager) {
super(context, map, clusterManager);
this.map = map;
}
@Override
protected void onBeforeClusterItemRendered(Point item, MarkerOptions markerOptions) {
markerOptions.flat(true);
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(195));
drawRadius(item);
super.onBeforeClusterItemRendered(item, markerOptions);
}
@Override
protected void onClusterRendered(Cluster<Point> cluster, Marker marker) {
super.onClusterRendered(cluster, marker);
for (Circle circle : circleList) {
circle.remove();
}
circleList.clear();
}
private void drawRadius(Point point) {
CircleOptions circleOptions = new CircleOptions()
.center(point.getPosition())
.strokeColor(Color.argb(50, 70, 70, 70))
.fillColor(Color.argb(100, 150, 150, 150))
.radius(point.getRadius());
Circle circle = map.addCircle(circleOptions);
circleList.add(circle);
}