41

I'm currently working on developing apps by using Google maps android API v2. My code is as follows. Suppose map has several markers and zoom up to show all markers in display.

LatLngBuilder.Builder builder = LatLngBounds.builder();
for(Marker m : markers){
    builder.include(m.getPosition());
}
LatLngBounds bounds = builder.build();
map.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 10);

This code is working fine but I want to stop animating when the zoom level reached to 17.0f; It seems map API does not have such method to control zoom level. Does anybody know any idea to solve this problem?

joao2fast4u
  • 6,868
  • 5
  • 28
  • 42
user2223820
  • 583
  • 1
  • 5
  • 12

17 Answers17

31

A recent update to the Google Maps API introduces the functions you require:

GoogleMap.setMaxZoomPreference()

GoogleMap.setMinZoomPreference()

It still does not prevent the animation from playing, though.

Dmitry Serov
  • 861
  • 11
  • 22
25

I have not found any direct solution in the Google Maps API. A potential solution to this problem consists in listening against the OnCameraChange event: Whenever this event triggers and the zoom level is above the maximum zoom level, it is possible to call animateCamera(). The resulting code would be the following:

@Override
public void onCameraChange(CameraPosition position) {
    float maxZoom = 17.0f;
    if (position.zoom > maxZoom)
        map_.animateCamera(CameraUpdateFactory.zoomTo(maxZoom));
}
Tisys
  • 938
  • 1
  • 8
  • 18
  • 3
    thanks for your commnet. i've tried this but it seems onCameraChange called after animating, so zoom level can be grater than 17.0 sometimes. – user2223820 Jun 22 '13 at 05:54
  • 12
    There is now a direct solution by using `GoogleMap.setMaxZoomPreference()` and `GoogleMap.setMinZoomPreference()` – Chris Stillwell Aug 03 '16 at 18:38
19

From Android doc: https://developers.google.com/maps/documentation/android-api/views

You may find it useful to set a prefered minimum and/or maximum zoom level. For example, this is useful to control the user's experience if your app shows a defined area around a point of interest, or if you're using a custom tile overlay with a limited set of zoom levels.

private GoogleMap mMap;
// Set a preference for minimum and maximum zoom.
mMap.setMinZoomPreference(6.0f);
mMap.setMaxZoomPreference(14.0f);
stkent
  • 19,772
  • 14
  • 85
  • 111
14

Here is the corresponding Java code for Arvis' solution which worked well for me:

private LatLngBounds adjustBoundsForMaxZoomLevel(LatLngBounds bounds) {
  LatLng sw = bounds.southwest;
  LatLng ne = bounds.northeast;
  double deltaLat = Math.abs(sw.latitude - ne.latitude);
  double deltaLon = Math.abs(sw.longitude - ne.longitude);

  final double zoomN = 0.005; // minimum zoom coefficient
  if (deltaLat < zoomN) {
     sw = new LatLng(sw.latitude - (zoomN - deltaLat / 2), sw.longitude);
     ne = new LatLng(ne.latitude + (zoomN - deltaLat / 2), ne.longitude);
     bounds = new LatLngBounds(sw, ne);
  }
  else if (deltaLon < zoomN) {
     sw = new LatLng(sw.latitude, sw.longitude - (zoomN - deltaLon / 2));
     ne = new LatLng(ne.latitude, ne.longitude + (zoomN - deltaLon / 2));
     bounds = new LatLngBounds(sw, ne);
  }

  return bounds;
}
Ernie
  • 1,210
  • 1
  • 14
  • 21
  • Thx a lot. I have a question about zoom coefficient. How translate android zoom level (17 in this thread) to `zoomN` ? – mrroboaat Oct 17 '13 at 08:48
  • Sorry I didn't need to do it yet ... so I don't know yet :-) – Ernie Oct 17 '13 at 20:11
  • Hello @kasimir, where have you put this code to control the max zoom level? Is it just a configuration when the GoogleMap object is created? – Ignacio Rubio Dec 17 '14 at 08:13
  • 1
    @IgnacioRubio Sorry don't know how to format code here, but try this: bounds = adjustBoundsForMaxZoomLevel(bounds); int padding = 10; // offset from edges of the map in pixels CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, padding); mGoogleMap.animateCamera(cu); – Ernie Dec 17 '14 at 09:53
  • This worked out well. If it isn't obvious – the greater the zoomN, the less the map is allowed to be zoomed in. – rrbrambley Apr 19 '15 at 17:41
  • Code has a mistake. Use `(zoomN - deltaX) / 2` instead `(zoomN - deltaX / 2)` – a.toropov Jan 26 '17 at 18:42
7

Same as Arvis solution but using Location's [distanceBetween()](http://developer.android.com/reference/android/location/Location.html#distanceBetween(double, double, double, double, float[])) method to calculate distance between to points:

@Override
public void zoomToMarkers(Set<Marker> markers) {

    LatLngBounds.Builder builder = new LatLngBounds.Builder();
    for (Marker marker : markers) {
        builder.include(marker.getPosition());
    }
    LatLngBounds bounds = builder.build();

    // Calculate distance between northeast and southwest
    float[] results = new float[1];
    android.location.Location.distanceBetween(bounds.northeast.latitude, bounds.northeast.longitude,
            bounds.southwest.latitude, bounds.southwest.longitude, results);

    CameraUpdate cu = null;
    if (results[0] < 1000) { // distance is less than 1 km -> set to zoom level 15
        cu = CameraUpdateFactory.newLatLngZoom(bounds.getCenter(), 15);
    } else {
        int padding = 50; // offset from edges of the map in pixels
        cu = CameraUpdateFactory.newLatLngBounds(bounds, padding);
    }
    if (cu != null) {
        mMap.moveCamera(cu);
    }
}
Jens
  • 6,243
  • 1
  • 49
  • 79
3

Before animate Camera you can check if SW and NE points of bounds are not too close and if necessary adjust bounds:

        ...
        LatLngBounds bounds = builder.Build();

        var sw = bounds.Southwest;
        var ne = bounds.Northeast;
        var deltaLat = Math.Abs(sw.Latitude - ne.Latitude);
        var deltaLon = Math.Abs(sw.Longitude - ne.Longitude);

        const double zoomN = 0.005; // set whatever zoom coefficient you need!!!
        if (deltaLat < zoomN) {
            sw.Latitude = sw.Latitude - (zoomN - deltaLat / 2);
            ne.Latitude = ne.Latitude + (zoomN - deltaLat / 2);
            bounds = new LatLngBounds(sw, ne);
        }
        else if (deltaLon < zoomN) {
            sw.Longitude = sw.Longitude - (zoomN - deltaLon / 2);
            ne.Longitude = ne.Longitude + (zoomN - deltaLon / 2);
            bounds = new LatLngBounds(sw, ne);
        }

        map.animateCamera(CameraUpdateFactory.NewLatLngBounds(bounds, 10);

ps. My example is in c# for Xamarin but you can easly adjust it for java

Arvis
  • 8,273
  • 5
  • 33
  • 46
2

Im not sure if this will work but can you try this

map.animateCamera(CameraUpdateFactory.zoomTo(10), 2000, null);

Hope it helps

Benil Mathew
  • 1,638
  • 11
  • 23
2

This is from the API reference for the include(position) you're using:

"Includes this point for building of the bounds. The bounds will be extended in a minimum way to include this point. More precisely, it will consider extending the bounds both in the eastward and westward directions (one of which may wrap around the world) and choose the smaller of the two. In the case that both directions result in a LatLngBounds of the same size, this will extend it in the eastward direction."

The map will zoom out until it can show all of the markers you're adding in your for loop.

If you want to only zoom out to 17 and still show markers, animate to zoom level 17 first, then get the bounds for it, and then add your markers.

@Override
public void onCameraChange(CameraPosition camPos) {

    if (camPos.zoom < 17 && mCurrentLoc != null) {
        // set zoom 17 and disable zoom gestures so map can't be zoomed out
        // all the way
        mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(position,17));
        mMap.getUiSettings().setZoomGesturesEnabled(false);
    }
    if (camPos.zoom >= 17) {
        mMap.getUiSettings().setZoomGesturesEnabled(true);
    }

    LatLngBounds visibleBounds =  mMap.getProjection().getVisibleRegion().latLngBounds;

//add the markers
1

@kasimir's approach sets a minimum number of degrees in either the latitude or longitude, and felt a little hard to read. So I tweaked it to just set a minimum on the latitude, which I felt like was a bit more readable:

private LatLngBounds adjustBoundsForMinimumLatitudeDegrees(LatLngBounds bounds, double minLatitudeDegrees) {
    LatLng sw = bounds.southwest;
    LatLng ne = bounds.northeast;
    double visibleLatitudeDegrees = Math.abs(sw.latitude - ne.latitude);

    if (visibleLatitudeDegrees < minLatitudeDegrees) {
        LatLng center = bounds.getCenter();
        sw = new LatLng(center.latitude - (minLatitudeDegrees / 2), sw.longitude);
        ne = new LatLng(center.latitude + (minLatitudeDegrees / 2), ne.longitude);
        bounds = new LatLngBounds(sw, ne);
    }

    return bounds;
}
Christopher Pickslay
  • 17,523
  • 6
  • 79
  • 92
1

Zoom Levels are the followings:

1f: World
5f: Landmass/continent
10f: City
15f: Streets
20f: Buildings
val setMin = 10f
val setMax = 20f

googleMap.setMaxZoomPreference(setMax)
googleMap.setMinZoomPreference(setMin)
0

What I ended up doing is creating my own buttons and disabling the default ones so I would have full control.

Something like this in the layout to place the buttons:

<LinearLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:layout_gravity="bottom"
    android:layout_alignParentRight="true"
    android:layout_alignParentBottom="true">

    <Button
        android:id="@+id/bzoomin"
        android:layout_width="55dp"
        android:layout_height="55dp"
        android:gravity="center"
        android:textSize="28sp"
        android:text="+" />
    <Button
            android:id="@+id/bzoomout"
            android:layout_width="55dp"
            android:layout_height="55dp"
            android:gravity="center"
            android:textSize="23sp"
            android:text="—" />
</LinearLayout>

Then this in the code to disable the default buttons and setup our new ones:

map.getUiSettings().setZoomControlsEnabled(false);

// setup zoom control buttons
Button zoomout = (Button) findViewById(R.id.bzoomout);
zoomout.setOnClickListener(new OnClickListener(){

    @Override
    public void onClick(View v) {
        if(map.getCameraPosition().zoom >= 8.0f){
            // Zoom like normal
            map.animateCamera(CameraUpdateFactory.zoomOut());
        }else{
            // Do whatever you want if user went too far
            Messages.toast_short(MapsActivity.this, "Maximum zoom out level reached");
        }
    }

});

Button zoomin = (Button) findViewById(R.id.bzoomin);
zoomin.setOnClickListener(new OnClickListener() {

    @Override
    public void onClick(View v) {
        if (map.getCameraPosition().zoom <= 14.0f) {
            // Zoom like normal
            map.animateCamera(CameraUpdateFactory.zoomIn());
        } else {
            // Do whatever you want if user went too far
            Messages.toast_short(MapsActivity.this, "Maximum zoom in level reached");
        }
    }
});
William W
  • 1,776
  • 6
  • 21
  • 40
  • 1
    Hi @William W. This solve the buttons, but what about the pinch&zoom with the fingers on the screen? – Ignacio Rubio Dec 16 '14 at 16:42
  • @IgnacioRubio You can disable all gestures with `map.getUiSettings().setAllGesturesEnabled(false);` or just pinch-to-zoom with `map.getUiSettings().setZoomGesturesEnabled(false);` – William W Dec 16 '14 at 17:10
  • 1
    But a map with zoomgestured disabled would have a bad user-experience. I mean, I'm looking for setting the zoom to a max level but I would like that the user could use both, buttons and finger gestures. I have found that it exists in the OSM API: https://code.google.com/p/osmdroid/issues/detail?id=418 But I'm using googlemaps, so I need to find a solution for this – Ignacio Rubio Dec 16 '14 at 17:17
  • 1
    @IgnacioRubio Very true that in most cases disabling pinch-to-zoom is bad UX. It's what I ended up doing in my case though. The only thing I tried was the answer from Tisys. However while it technically works, it doesn't work very well and is mostly frustrating for the user. I haven't looked into some of the other suggestions on this page. – William W Dec 16 '14 at 17:24
  • I have used the Tisys solution. It works fine for me. It's true that for an instant of time, the user could zoom more than the max zoom level (because onCameraChange is called after animating). But the zoom is quickly restablished to max. (It would be better if the API had the "setMaxZoomLevel" method as the OSM but for me it's perfect) – Ignacio Rubio Dec 17 '14 at 08:34
0

With com.google.android.gms:play-services-maps:9.4.0 you can easily set min/max zoom. With GoogleMap.setMinZoomPreference() and GoogleMap.setMaxZoomPreference() you can set a prefered minimum and/or maximum zoom level. More see here.

wwang
  • 605
  • 1
  • 5
  • 13
0

We can not restrict map zoomin feature directly, but we can try to get same feature like this.

add map.setOnCameraChangeListener

final float maxZoom = 10.0f;

@Override
public void onCameraChange(CameraPosition position) {

    if (position.zoom > maxZoom)
        map.animateCamera(CameraUpdateFactory.zoomTo(maxZoom));
}
R_K
  • 803
  • 1
  • 7
  • 18
0

On the new Google Maps 9.8

com.google.android.gms:play-services-maps:9.8.0

This is how I did and worked

    googleMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() {
        @Override
        public void onCameraMove() {
            Log.d(App.TAG, "onCameraMove");

            CameraPosition position = googleMap.getCameraPosition();

            float maxZoom = 9.0f;
            if (position.zoom > maxZoom) {

                googleMap.setMinZoomPreference(maxZoom);
            }

            Log.d(App.TAG, "position.zoom = " + position.zoom);

        }
    });
user2373653
  • 3
  • 1
  • 2
0
map.setMinZoomPreference(floatValue);
Paul Roub
  • 36,322
  • 27
  • 84
  • 93
-2

You can get the max zoom level by calling it getMaxZoomLevel() and then set that value:

mGoogleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(fromPosition, getMaxZoomLevel()));
kgdesouz
  • 1,966
  • 3
  • 16
  • 21
Ashish Agrawal
  • 1,977
  • 2
  • 18
  • 32
  • 1
    Hi. i tried this. newLatLngZoom seems not able to use LatLngBounds. i want to zoom all markers including AND zoom level <= 17.0. – user2223820 Jun 22 '13 at 07:36
-4

The map has a property called maxZoom. Simply set this to your value when you create your map

Linga
  • 10,379
  • 10
  • 52
  • 104