在Google地图Android API V2中设置最大缩放级别

41

我目前正在使用Google地图Android API v2开发应用程序。 我的代码如下。 假设地图上有几个标记,并缩放以显示所有标记。

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

这段代码运行良好,但我希望在缩放级别达到17.0f时停止动画; 似乎地图API没有控制缩放级别的方法。 有人知道解决这个问题的任何想法吗?

17个回答

31

谷歌地图API的最新更新引入了您所需的功能:

GoogleMap.setMaxZoomPreference()

GoogleMap.setMinZoomPreference()

尽管如此,它仍然不能阻止动画播放。


1
要重置最大和最小值,您可以调用 **map.resetMinMaxZoomPreference()**。 - Amir Hossein Ghasemi

25

我在Google Maps API中没有找到任何直接的解决方案。一个可能的解决方法是监听OnCameraChange事件:每当此事件触发且缩放级别高于最大缩放级别时,可以调用animateCamera()。相关代码如下:

@Override
public void onCameraChange(CameraPosition position) {
    float maxZoom = 17.0f;
    if (position.zoom > maxZoom)
        map_.animateCamera(CameraUpdateFactory.zoomTo(maxZoom));
}

3
感谢您的评论。我尝试了这个方法,但似乎onCameraChange在动画完成后才被调用,因此缩放级别有时可能大于17.0。 - user2223820
12
现在有一种直接的解决方法,可以使用GoogleMap.setMaxZoomPreference()GoogleMap.setMinZoomPreference() - Chris Stillwell

19

来自Android文档: https://developers.google.com/maps/documentation/android-api/views

如果您的应用程序显示围绕兴趣点定义的区域或者使用具有有限缩放级别的自定义瓦片覆盖层,则设置首选最小和/或最大缩放级别可能很有用。

private GoogleMap mMap;
// Set a preference for minimum and maximum zoom.
mMap.setMinZoomPreference(6.0f);
mMap.setMaxZoomPreference(14.0f);

14

这是Arvis的解决方案的Java代码,对我非常有效:

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

非常感谢。我有一个关于缩放系数的问题。如何将安卓的缩放级别(在此线程中为17)转换为 zoomN - mrroboaat
抱歉,我还没有需要这样做的情况...所以我还不知道 :-) - Ernie
你好@kasimir,你把控制最大缩放级别的代码放在哪里了?它只是在创建GoogleMap对象时进行配置吗? - Ignacio Rubio
1
@IgnacioRubio 抱歉不知道如何在此处格式化代码,但请尝试以下内容:bounds = adjustBoundsForMaxZoomLevel(bounds);int padding = 10; // 像素偏移量,相对于地图边缘 CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, padding); mGoogleMap.animateCamera(cu); - Ernie
这个效果很好。如果不是很明显的话 - zoomN越大,地图就允许缩小的程度就越小。 - rrbrambley
代码有错误。使用(zoomN - deltaX) / 2代替(zoomN - deltaX / 2) - a.toropov

7
与Arvis解决方案相同,但使用Location的[distanceBetween()](http://developer.android.com/reference/android/location/Location.html#distanceBetween(double, double, double, double, float[]))方法来计算两点之间的距离:
@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);
    }
}

3
在动画相机之前,您可以检查边界框的SW和NE点是否不太接近,如果必要,可以调整边界框:
        ...
        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);

提示:我的示例是针对Xamarin的C#,但您可以轻松地将其调整为Java。


谢谢,我已在下面的答案中添加了相应的Java代码。 - Ernie
代码有错误。使用(zoomN - deltaX) / 2代替(zoomN - deltaX / 2) - a.toropov

2

我不确定这个方法是否有效,但你可以试一下:

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

希望能对您有所帮助


不幸的是,这个并没有很好地工作。还是谢谢你的帮助。 - user2223820

2
这段文字来自你正在使用的 include(position)API参考文档
“在构建边界时包括此点。边界将以最小的方式扩展以包括此点。 更准确地说,它将考虑向东和向西两个方向(其中一个可能绕过世界)扩展边界,并选择两者中较小的那个。如果两个方向的结果产生相同大小的LatLngBounds,则会向东扩展它。”
地图将缩放到能够显示您在 for 循环中添加的所有标记。
如果您只想缩小到 17 并仍然显示标记,请先动画缩放到缩放级别 17,然后获取其边界,然后添加您的标记。
@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的做法设置了纬度或经度中的最小度数,但有些难以理解。因此,我对其进行了调整,仅在纬度上设置了最小值,我认为这更易于阅读:

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

1
缩放级别如下:
1f: World
5f: Landmass/continent
10f: City
15f: Streets
20f: Buildings
val setMin = 10f
val setMax = 20f

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接