Android地图v2缩放以显示所有标记

Asa*_*hna 276 android google-maps google-maps-api-2 google-maps-android-api-2

我有10个标记GoogleMap.我想尽可能放大并保持所有标记在视野中?在早期版本中,这可以实现,zoomToSpan()但在v2中,我不知道如何做到这一点.此外,我知道需要看到的圆的半径.

and*_*ndr 781

您应该使用CameraUpdate该类(可能)执行所有程序化地图移动.

为此,首先计算所有标记的边界,如下所示:

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

然后使用工厂获取运动描述对象CameraUpdateFactory::

int padding = 0; // offset from edges of the map in pixels
CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, padding);
Run Code Online (Sandbox Code Playgroud)

最后移动地图:

googleMap.moveCamera(cu);
Run Code Online (Sandbox Code Playgroud)

或者如果你想要一个动画:

googleMap.animateCamera(cu);
Run Code Online (Sandbox Code Playgroud)

就这样 :)

澄清1

几乎所有的移动方法都要求Map对象通过布局过程.您可以使用addOnGlobalLayoutListener构造等待这种情况发生.详细信息可以在对此答案的评论和剩余答案中找到.您还可以在此处找到用于设置地图范围addOnGlobalLayoutListener完整代码.

澄清2

一条评论指出,仅将此方法用于一个标记会导致地图缩放设置为"奇异"缩放级别(我相信这是给定位置可用的最大缩放级别).我认为这是预期的,因为:

  1. LatLngBounds bounds实例将具有northeast等于的属性southwest,这意味着由此覆盖的地球部分bounds恰好为零.(这是合乎逻辑的,因为单个标记没有区域.)
  2. 通过传递boundsCameraUpdateFactory.newLatLngBounds你基本上请求计算这样的缩放级别bounds(具有零区域)将覆盖整个地图视图.
  3. 您实际上可以在一张纸上执行此计算.作为答案的理论缩放级别是+∞(正无穷大).在实践中,Map对象不支持该值,因此它被钳位到给定位置允许的更合理的最大级别.

另一种说法:Map对象如何知道它应该为单个位置选择什么缩放级别?也许最佳值应该是20(如果它代表一个特定的地址).或者11(如果它代表一个小镇).或者可能是6(如果它代表一个国家).API不是那么聪明,决定取决于你.

因此,您应该只检查是否markers只有一个位置,如果是,请使用以下方法之一:

  • CameraUpdate cu = CameraUpdateFactory.newLatLng(marker.getPosition()) - 转到标记位置,保持当前缩放级别不变.
  • CameraUpdate cu = CameraUpdateFactory.newLatLngZoom(marker.getPosition(), 12F) - 转到标记位置,将缩放级别设置为任意选择的值12.

  • 应该注意的是,移动不能从onCreate调用发生,必须创建视图.我需要使用addOnGlobalLayoutListener来获取适当的样本. (21认同)
  • googleMap .setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback(){@ Overver public void onMapLoaded(){googleMap.moveCamera(cu);}}); 这样可以避免测量误差. (9认同)
  • @Bar嗯,这部分是正确的.确切地说:*某些*移动方法在创建地图对象后无法正常工作.原因是地图对象尚未被*测量*,即它没有经历布局过程.一个典型的解决方法是使用`addOnGlobalLayoutListener()`或`post()`和适当的`Runnable`.这正是为什么无法在`onCreate`中获取标记屏幕坐标的原因 - 请参阅http://stackoverflow.com/q/14429877/1820695但是您甚至可以在布局发生之前使用某些方法 - 例如.`CameraUpdateFactory.newLatLngBounds()`with*4 params*. (6认同)

Zum*_*med 113

谷歌地图V2

以下解决方案适用于Android Marshmallow 6(API 23,API 24,API 25).它也适用于Xamarin.

LatLngBounds.Builder builder = new LatLngBounds.Builder();

//the include method will calculate the min and max bound.
builder.include(marker1.getPosition());
builder.include(marker2.getPosition());
builder.include(marker3.getPosition());
builder.include(marker4.getPosition());

LatLngBounds bounds = builder.build();

int width = getResources().getDisplayMetrics().widthPixels;
int height = getResources().getDisplayMetrics().heightPixels;
int padding = (int) (width * 0.10); // offset from edges of the map 10% of screen

CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, width, height, padding);

mMap.animateCamera(cu);
Run Code Online (Sandbox Code Playgroud)

  • 为了更好看的填充,使用高度而不是宽度,取20%而不是10%. (6认同)
  • 接受的答案有时会导致奇怪的缩放。这就像一个魅力。这是一个更好的答案。 (3认同)
  • 这个答案比接受的答案更好,接受的答案会导致一些奇怪的行为。 (2认同)

Eug*_*noy 13

所以

我需要使用addOnGlobalLayoutListener来获取适当的样本

例如,您的Google地图位于RelativeLayout内:

RelativeLayout mapLayout = (RelativeLayout)findViewById(R.id.map_layout);
mapLayout.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            //and write code, which you can see in answer above
        }
    });
Run Code Online (Sandbox Code Playgroud)


chr*_*rjs 13

我无法使用onGlobalLayoutlistener,所以这是另一种防止"Map size can't be 0. Most likely, layout has not yet occured for the map view. Either wait until layout has occurred or use newLatLngBounds(LatLngBounds, int, int, int) which allows you to specify the map's dimensions."错误的解决方案 :

mMap.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() { 
@Override 
public void onMapLoaded() { 
    mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(builder.build(), 15));
 } 
});
Run Code Online (Sandbox Code Playgroud)


BK1*_*K19 8

对我来说很好.

从这段代码中,我在地图屏幕上显示具有特定缩放的多个标记.

//声明变量

private LatLngBounds bounds;
private LatLngBounds.Builder builder;
Run Code Online (Sandbox Code Playgroud)

//使用可绘制图标添加多个标记点的方法

private void drawMarker(LatLng point, String text) {

        MarkerOptions markerOptions = new MarkerOptions();
        markerOptions.position(point).title(text).icon(BitmapDescriptorFactory.fromResource(R.drawable.icon));
        mMap.addMarker(markerOptions);
        builder.include(markerOptions.getPosition());

    }
Run Code Online (Sandbox Code Playgroud)

//用于添加地图上可见的多个标记

@Override
    public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;
        builder = new LatLngBounds.Builder();
    for (int i = 0; i < locationList.size(); i++) {

        drawMarker(new LatLng(Double.parseDouble(locationList.get(i).getLatitude()), Double.parseDouble(locationList.get(i).getLongitude())), locationList.get(i).getNo());

     }
     bounds = builder.build();
     CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, 0);
     mMap.animateCamera(cu);
Run Code Online (Sandbox Code Playgroud)


Jyo*_*ngh 5

注意- 这不是原始问题的解决方案。这是上面讨论的子问题之一的解决方案。

@andr澄清 2 的解决方案-

当边界中只有一个标记并且缩放级别设置为非常高的级别(级别 21)时,这确实有问题。并且谷歌此时没有提供任何设置最大缩放级别的方法。当有超过 1 个标记但它们都非常接近时,也会发生这种情况。然后也会出现同样的问题。

解决方案- 假设您希望地图的缩放级别永远不会超过 16。然后做完之后——

CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, padding);
mMap.moveCamera(cu);
Run Code Online (Sandbox Code Playgroud)

检查您的缩放级别是否已超过 16 级(或您想要的任何级别)-

float currentZoom = mMap.getCameraPosition().zoom;
Run Code Online (Sandbox Code Playgroud)

如果此级别大于 16,只有在标记非常少或所有标记彼此非常接近时才会出现这种情况,那么只需将缩放级别设置为 16,就可以在该特定位置缩小地图。

mMap.moveCamera(CameraUpdateFactory.zoomTo(16));
Run Code Online (Sandbox Code Playgroud)

这样你就永远不会遇到@andr 也很好地解释了“奇怪”缩放级别的问题。


Ami*_*kur 5

这会有所帮助..来自 google apis demos

private List<Marker> markerList = new ArrayList<>();
Marker marker = mGoogleMap.addMarker(new MarkerOptions().position(geoLatLng)
                .title(title));
markerList.add(marker);
    // Pan to see all markers in view.
    // Cannot zoom to bounds until the map has a size.
    final View mapView = getSupportFragmentManager().findFragmentById(R.id.map).getView();
    if (mapView!=null) {
        if (mapView.getViewTreeObserver().isAlive()) {
            mapView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @SuppressWarnings("deprecation") // We use the new method when supported
                @SuppressLint("NewApi") // We check which build version we are using.
                @Override
                public void onGlobalLayout() {
                    //Calculate the markers to get their position
                    LatLngBounds.Builder b = new LatLngBounds.Builder();
                    for (Marker m : markerList) {
                        b.include(m.getPosition());
                    }
                    // also include current location to include in the view
                    b.include(new LatLng(mLocation.getLatitude(),mLocation.getLongitude()));

                    LatLngBounds bounds = b.build();
                    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
                        mapView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                    } else {
                        mapView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                    }
                    mGoogleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 50));
                }
            });
        }
    }
Run Code Online (Sandbox Code Playgroud)

要获得清晰的信息,请查看此网址。 https://github.com/googlemaps/android-samples/blob/master/ApiDemos/app/src/main/java/com/example/mapdemo/MarkerDemoActivity.java