Setting max zoom level in google maps android api

2019-01-10 19:15发布

问题:

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?

回答1:

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));
}


回答2:

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.



回答3:

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;
}


回答4:

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);


回答5:

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);
    }
}


回答6:

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



回答7:

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


回答8:

@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;
}


回答9:

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

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

Hope it helps



回答10:

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");
        }
    }
});


回答11:

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.



回答12:

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));
}


回答13:

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);

        }
    });


回答14:

map.setMinZoomPreference(floatValue);


回答15:

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

mGoogleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(fromPosition, getMaxZoomLevel()));


回答16:

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