32

I'm using the library Google Maps Utility for Android which allows to create clustering int he maps and I need to show a custom InfoWindow but I can't find any method to do this. In order to show the info window, I have the following class, and in the method onClusterItemRendered is where I have access to the info of the marker:

class MyClusterRenderer extends DefaultClusterRenderer<MarkerItem> {

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

    @Override
    protected void onBeforeClusterItemRendered(MarkerItem item,
            MarkerOptions markerOptions) {
        super.onBeforeClusterItemRendered(item, markerOptions);
        markerOptions.title(String.valueOf(item.getMarkerId()));
    }

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

Is there anybody who has used the library and knows how to show a custom InfoWindow such as the way it was used in the Google Maps? Like:

getMap().setInfoWindowAdapter(new InfoWindowAdapter() {

    @Override
    public View getInfoWindow(Marker arg0) {
        return null;
    }

    @Override
    public View getInfoContents(Marker arg0) {
        return null;
    }
});
ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
noloman
  • 11,411
  • 20
  • 82
  • 129

2 Answers2

62

Yes, this can be done. ClusterManager maintains two MarkerManager.Collections:

  • one for cluster markers, and
  • one for individual item markers

You can set a custom InfoWindowAdapter for each of these kinds of markers independently.


Implementation

First, install your ClusterManager's MarkerManager as the map's InfoWindowAdapter:

ClusterManager<MarkerItem> clusterMgr = new ClusterManager<MarkerItem>(context, map);
map.setInfoWindowAdapter(clusterMgr.getMarkerManager());

Next, install your custom InfoWindowAdapter as the adapter for one or both of the marker collections:

clusterMgr.getClusterMarkerCollection().setOnInfoWindowAdapter(new MyCustomAdapterForClusters());
clusterMgr.getMarkerCollection().setOnInfoWindowAdapter(new MyCustomAdapterForItems());

The final piece is mapping the raw Marker object that you'll receive in your custom InfoWindowAdapter's callback to the ClusterItem object(s) that you added to the map in the first place. This can be achieved using the onClusterClick and onClusterItemClick listeners, as follows:

map.setOnMarkerClickListener(clusterMgr);
clusterMgr.setOnClusterClickListener(new OnClusterClickListener<MarkerItem>() {
    @Override
    public boolean onClusterClick(Cluster<MarkerItem> cluster) {
        clickedCluster = cluster; // remember for use later in the Adapter
        return false;
    }
});
clusterMgr.setOnClusterItemClickListener(new OnClusterItemClickListener<MarkerItem>() {
    @Override
    public boolean onClusterItemClick(MarkerItem item) {
        clickedClusterItem = item;
        return false;
    }
});

Now you have everything you need to assemble your custom InfoWindow content in your respective Adapters! For example:

class MyCustomAdapterForClusters implements InfoWindowAdapter {
    @Override
    public View getInfoContents(Marker marker) {
        if (clickedCluster != null) {
            for (MarkerItem item : clickedCluster.getItems()) {
                // Extract data from each item in the cluster as needed
            }
        }
        // build your custom view
        // ...
        return view;
    }
}
RonR
  • 835
  • 6
  • 11
  • 4
    Good job! I just want to warn people, i haven't noticed a piece of code: `map.setOnMarkerClickListener(clusterMgr);` and the callback was never hit. It's obviously needed to do as commented in source code: `/*Sets a callback that's invoked when an individual ClusterItem is tapped. Note: For thislistener to function, the ClusterManager must be added as a click listener to the map. */ public void setOnClusterItemClickListener(OnClusterItemClickListener listener) { mOnClusterItemClickListener = listener; mRenderer.setOnClusterItemClickListener(listener); }` – Dmitry Gryazin Jul 07 '14 at 11:06
  • I'm not quite sure what you mean? I do call map.setOnMarkerClickListener(clusterMgr) in my sample code above, immediately before setting the onCluster and onClusterItem click listeners. – RonR Jul 08 '14 at 11:36
  • 3
    All is ok, it was just my mistake, so I wanted to highlight this point – Dmitry Gryazin Jul 08 '14 at 11:50
  • Was struggling on the similar issue until stumbled upon your comment. It opened my eyes :) Thanks – Drew Sep 24 '14 at 19:08
  • It looks like there's a far better way to do this now, from 0.3.2 forward, https://github.com/googlemaps/android-maps-utils/issues/48 – rfay Oct 22 '14 at 13:32
  • setOnInfoWindowAdapter showing unresolved reference – ABDUL RAHMAN Dec 02 '20 at 11:07
0

So basically you have your class starting like this:

private class MarkerItemClusterRenderer extends
        DefaultClusterRenderer<MarkerItem> {
    public MarkerItemClusterRenderer(Context context, GoogleMap map,
            ClusterManager<MarkerItem> clusterManager) {
    ...

So in that parameter map of the type GoogleMap is where you have to specify your setInfoWindowAdapter.

noloman
  • 11,411
  • 20
  • 82
  • 129