0

I am using the GooglePlaces API to populate things around the user, everything works fine for now. I use the icon returned by the API to set for each Marker. It's perfectly good (except that some icon are ugly but well), the problem is that it becomes over-stacked whenever I zoom-out (around zoom level 13) I tried to implement something to hide the Marker whenever I zoom-out too much, or tried to find a math formula to change the alpha property of the Marker so they smoothly hide themselves the more I zoom-out but those solutions are not very pleasant.

map.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() {
    @Override
    public void onCameraChange(CameraPosition cameraPosition) {
        float zoomLevel = cameraPosition.zoom;
        if (zoomLevel < 13) {
            for (int i = 0; i < places.size(); i++)
                places.get(i).setVisible(false);
        } else {
            for (int i = 0; i < places.size(); i++) {
                places.get(i).setVisible(true);
            }
        }
    }
});

Is there any way to handle such a case ?

I have one example : the AirBnb application (but I don't really understand what they actually perform behind the scene).

Swann
  • 2,413
  • 2
  • 20
  • 28

1 Answers1

0

It seems that Airbnb simply hides/shows specific markers when the zoom level changes.

You could use Marker Clustering so markers join together into a single group when zoomed out. If that's not what you want, read on.

I answered a similar question regarding polylines here.

The solution is to create a sparse array, which for specific zoom levels, contains specific markers. E.g.:

// Zoom level 16 and up
List<Marker> markers = new ArrayList<Marker>();
markers.add(mMap.addMarker(new MarkerOptions()
        .position(new LatLng(48.867068, 2.351503))));
...
// Markers are hidden by default
for (Marker marker : markers) marker.setVisible(false);

mZoomMarkers.put(16, markers);

Then initialize your map, revealing some of the markers:

SparseArray<List<Marker>> mZoomMarkers = new SparseArray<List<Marker>>();
int mZoomLevel = 16;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ...
    // Zoom to 16
    mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(point, mZoomLevel), 1000, null);
    // Reveal markers
    for(int i=0; i<mZoomMarkers.size(); i++) {
        // Loop until zoom level is reached
        if  (mZoomMarkers.keyAt(i) > zoomLevel) break;
        showMarkers(mZoomMarkers.get(mZoomMarkers.keyAt(i)));
    }
    ...
}

private void showMarkers(List<Marker> markers) {
    if (markers != null) {
        for (Marker marker : markers) marker.setVisible(true);
    }
}

private void hideMarkers(List<Marker> markers) {
    if (markers != null) {
        for (Marker marker : markers) marker.setVisible(false);
    }
}

Finally set up a zoom level listener to add/remove markers accordingly:

mMap.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() {
    @Override
    public void onCameraChange(CameraPosition cameraPosition) {
        /* Note that because we are casting the zoomLevel to int,
         * it will be considered as changed only when it reaches
         * a new integer when rounded (e.g. 5.0, 6.0 etc.) */
        int newZoomLevel = (int) cameraPosition.zoom;
        if (newZoomLevel != mZoomLevel) {
            Log.d(TAG, "New zoom level: " + newZoomLevel);
            // Loop all the changed zoom levels
            // E.g. zoomed-out from 15 to 13, then hide [14, 15]
            if (newZoomLevel < mZoomLevel) { // Zoomed out
                for (int i=1; i<=mZoomLevel-newZoomLevel; i++)
                    hideMarkers(mZoomMarkers.get(newZoomLevel + i));
            } else { // Zoomed-in
                for (int i=1; i<=newZoomLevel-mZoomLevel; i++)
                    showMarkers(mZoomMarkers.get(mZoomLevel + i));
            }
            mZoomLevel = newZoomLevel;
        }
    }
});
Community
  • 1
  • 1
Simas
  • 43,548
  • 10
  • 88
  • 116