Without using the ClusterManager, I use HashMap to put the Marker and ID into the HashMap, and get the ID in the OnMarkClick method and get the data from database. It's works
markers.put(addNewMarker(geoPoint), objectId);
private Marker addNewMarker(ParseGeoPoint parseGeoPoint) {
double latitude = parseGeoPoint.getLatitude();
double longitude = parseGeoPoint.getLongitude();
return googleMap.addMarker(new MarkerOptions().position(
new LatLng(latitude, longitude)));
}
#Override
public boolean onMarkerClick(Marker marker) {
String objectId = markers.get(marker);
if (null == objectId) {
return false;
}
getMemoryBriefInfo(objectId);
return true;
}
But now I need to use the ClusterManager to cluster multiple markers into number.
The problems is It seems there is no way to implement this, in the demo of Google, it just add the Items into the Cluster.
There is a OnMarkerClick method in the ClusterManager class, but I don't how to Override this and set with my own unique ID.
there is a global solution for you that help to add title, snippet and icon so you can get what you want.
Modify your ClusterItem Object and add 3 variables :
public class MyItem implements ClusterItem {
private final LatLng mPosition;
BitmapDescriptor icon;
String title;
String snippet;
public MyItem(BitmapDescriptor ic,Double lat , Double lng,String tit ,String sni)
{
mPosition = new LatLng(lat,lng);
icon = ic;
title = tit;
snippet = sni;
}
And after you create your costume render :
public class OwnRendring extends DefaultClusterRenderer<MyItem> {
public OwnRendring(Context context, GoogleMap map,
ClusterManager<MyItem> clusterManager) {
super(context, map, clusterManager);
}
protected void onBeforeClusterItemRendered(MyItem item, MarkerOptions markerOptions) {
markerOptions.icon(item.getIcon());
markerOptions.snippet(item.getSnippet());
markerOptions.title(item.getTitle());
super.onBeforeClusterItemRendered(item, markerOptions);
}
}
After that just put this line in your SetUpCluster() function before addItems():
mClusterManager.setRenderer(new OwnRendring(getApplicationContext(),mMap,mClusterManager));
Related
I have a DefaultClusterRenderer class and my own ClusterItem, which I am using as marker on the map. I am setting the title and snippet with MarkerOptions, so I can grap them on my onInfoWindowClick event. I wanna start a new Activity, depends on which infoWindow the user clicked, but I cant add a tag to MarkerOptions, so I cant get the tag in my onInfoWindowClick method via the Marker parameter.
I am looking for a good solution to add an id to each ClusterItem and get the id via Marker in onInfoWindowClick.
public class OwnClusterRendering extends DefaultClusterRenderer<GeoPoint> {
private GoogleMap map;
public OwnClusterRendering(Context context, GoogleMap map, ClusterManager<GeoPoint> clusterManager) {
super(context, map, clusterManager);
this.map = map;
}
protected void onBeforeClusterItemRendered(GeoPoint geoPoint, MarkerOptions markerOptions) {
markerOptions.icon(geoPoint.getIcon());
markerOptions.snippet(geoPoint.getSnippet());
markerOptions.title(geoPoint.getTitle());
super.onBeforeClusterItemRendered(geoPoint, markerOptions);
}
}
MyCustomWindowAdapter:
#Override
public void onInfoWindowClick(Marker marker) {
Log.d("test", marker.getTitle());
Log.d("test", marker.getSnippet());
Log.d("test", marker.getId());
Log.d("test", String.valueOf(marker.getTag()));
// Intent intent = new Intent(context, StoneInfoSliderActivity.class);
// context.startActivity(intent);
}
Solved it with the following method from DefaultClusterRenderer<>
#Override
protected void onClusterItemRendered(GeoPoint geoPoint, Marker marker) {
marker.setTag(geoPoint.getId());
super.onClusterItemRendered(geoPoint, marker);
}
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
Android marker-clustering
MarkerManager.java
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);
}
This question already has answers here:
Google map marker is replaced by bounding rectangle on zoom
(3 answers)
Closed 6 years ago.
I'm trying to implement a cluster marker on my map,first, it shows me the cluster marker but when i zoom in, that expand and also show white square, i'll add some images to explain it better.
images
public class MyItem implements ClusterItem {
private final LatLng mPosition;
String Title = "";
int Icon;
public MyItem(double lat, double lng, String title, int icon) {
mPosition = new LatLng(lat, lng);
Title = title;
Icon = icon;
}
#Override
public LatLng getPosition() {
return mPosition;
}
public String getTitle() {
return Title;
}
public int getIcon() {
return Icon;
}
}
class OwnIconRendered extends DefaultClusterRenderer<MyItem> {
public OwnIconRendered() {
super(MapActivity.this, googleMap, mClusterManager);
}
#Override
protected void onBeforeClusterItemRendered(MyItem item, MarkerOptions markerOptions) {
markerOptions.icon(BitmapDescriptorFactory.fromResource(item.getIcon()));
markerOptions.title(item.getTitle());
super.onBeforeClusterItemRendered(item, markerOptions);
}
#Override
protected void onBeforeClusterRendered(Cluster<MyItem> cluster, MarkerOptions markerOptions) {
super.onBeforeClusterRendered(cluster, markerOptions);
}
}
There is an opened issue on gmaps-api-issues, look here: https://code.google.com/p/gmaps-api-issues/issues/detail?id=9765
Also look here: Google map marker is replaced by bounding rectangle on zoom
Some workarounds are also described there.
i'm developing my first app and i created the following map viewer activity:
public class MapViewer extends Activity implements OnInfoWindowClickListener, ClusterManager.OnClusterClickListener<MyItem> {
private GoogleMap map;
private LatLng defaultLatLng = new LatLng(X, Y);
private int zoomLevel = 5;
private Database db = new Database(this);
private ClusterManager<MyItem> mClusterManager;
private LatLngBounds allowedBounds;
private final LatLng northeast = new LatLng(A, B);
private final LatLng southwest = new LatLng(C, D);
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mapviewer);
LatLngBounds.Builder builder = new LatLngBounds.Builder();
builder.include(northeast);
builder.include(southwest);
allowedBounds = builder.build();
try {
map = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();
if (map != null) {
map.setMyLocationEnabled(true);
map.setMapType(GoogleMap.MAP_TYPE_NORMAL);
map.getUiSettings().setRotateGesturesEnabled(false);
map.moveCamera(CameraUpdateFactory.newLatLngZoom(defaultLatLng, zoomLevel));
mClusterManager = new ClusterManager<MyItem>(this, map);
mClusterManager.setRenderer(new MyClusterRenderer(this, map, mClusterManager));
mClusterManager.setOnClusterClickListener(this);
map.setOnCameraChangeListener(mClusterManager);
map.setOnMarkerClickListener(mClusterManager);
map.setInfoWindowAdapter(new ClusterInfoWindow(getLayoutInflater()));
map.setOnInfoWindowClickListener(this);
addItems();
}
} catch (NullPointerException e) {
e.printStackTrace();
}
}
}
As you can see i set a listener to map object
map.setOnCameraChangeListener(mClusterManager);
that adds or removes clusters on markers groups, according to zoom level.
Now i would add a listener that checks if user moves on map within some bounds:
map.setOnCameraChangeListener(new OnCameraChangeListener() {
#Override
public void onCameraChange(CameraPosition cameraPosition) {
checkBounds();
}
});
But it doesn't work. It works only if i remove the previous listener (mClusterManager).
So, how to make both listener working on the same map object?
Thank you in advance for your replies and sorry for my english.
As there's only a set method and no add method, you can only set one listener at a time. But you could delegate from the one listener to the other like this:
map.setOnCameraChangeListener(new OnCameraChangeListener() {
#Override
public void onCameraChange(CameraPosition cameraPosition) {
checkBounds();
mClusterManager.onCameraChange(cameraPosition);
}
});
Of course mClusterManager does not need to implement the CameraChangeListener interface any more but just needs a method public void onCameraChange(CameraPosition cameraPosition).
I'm using Google Maps Android API Utility Library in order to show several markers in a map in a clustered way.
I've followed the instructions to make it work, as well as taking a look at the examples in the library, but I can't figure out how to show an InfoWindow when a marker is clicked.
I guess getMap().setOnMarkerClickListener(mClusterManager); is the one managing the onClick events, and if commented out, I can override it using getMap().setInfoWindowAdapter(new InfoWindowAdapter() {)); but I have no access to my custom marker object.
Nevertheless, if I use getMap().setOnMarkerClickListener(mClusterManager);, I can't find a way to show the InfoWindow when a marker has been clicked.
Does anybody have any idea about how to achieve this?
Thanks a lot in advance!
You need to extend the DefaultClusterRenderer class and override the onBeforeClusterItemRendered, attaching the title to the MarkerOptions object passed as argument.
After that, you can pass your implementation to the ClusterManager.
Example:
class MyItem implements ClusterItem {
private LatLng mPosition;
private String mTitle;
public MyItem(LatLng position){
mPosition = position;
}
#Override
public LatLng getPosition() {
return mPosition;
}
public String getTitle() {
return mTitle;
}
public void setTitle(String title) {
mTitle = title;
}
}
class MyClusterRenderer extends DefaultClusterRenderer<MyItem> {
public MyClusterRenderer(Context context, GoogleMap map,
ClusterManager<MyItem> clusterManager) {
super(context, map, clusterManager);
}
#Override
protected void onBeforeClusterItemRendered(MyItem item, MarkerOptions markerOptions) {
super.onBeforeClusterItemRendered(item, markerOptions);
markerOptions.title(item.getTitle());
}
#Override
protected void onClusterItemRendered(MyItem clusterItem, Marker marker) {
super.onClusterItemRendered(clusterItem, marker);
//here you have access to the marker itself
}
}
And then you can use it in this way:
ClusterManager<MyItem> clusterManager = new ClusterManager<MyItem>(this, getMap());
clusterManager.setRenderer(new MyClusterRenderer(this, getMap() ,clusterManager));