Android Map v2缩放以显示所有标记


Answers:


809

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

为此,首先像这样计算所有标记的边界:

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

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

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

最后移动地图:

googleMap.moveCamera(cu);

或者,如果您想要动画:

googleMap.animateCamera(cu);

就这样 :)

澄清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。

21
应该注意的是,移动不能从onCreate调用发生,必须创建视图。我需要使用addOnGlobalLayoutListener来获取适当的示例。
巴鲁什甚至

6
@Bar好吧,这部分是正确的。准确地说:创建地图对象后,某些移动方法无法立即使用。原因是尚未测量地图对象,即它尚未经过布局过程。典型的修复方法是使用addOnGlobalLayoutListener()post()搭配适当的工具Runnable。这正是无法获取标记屏幕坐标的原因onCreate-请参阅stackoverflow.com/q/14429877/1820695但是,即使在布局发生之前,您也可以使用某些方法-例如。CameraUpdateFactory.newLatLngBounds()4个参数
andr

1
伙计,您保存了我的一天……实际上是我自己尝试做的事情,手动计算边界,并在其中插入标记时进行缩放……工作起来很丑陋,但是用您的简单方法,它就像一种魅力。谢谢
Bibu 2014年

9
googleMap .setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback(){@Override public void onMapLoaded(){googleMap.moveCamera(cu);}}); 这样可以避免测量错误。
拉姆兹2014年

1
否则,它会起作用,但是当地图上只有一个标记时,它会缩放到一定的怪异程度,使地图变得模糊。如何解决这个问题?
Utsav Gupta 2014年

124

Google Map V2

以下解决方案适用于Android Marshmallow 6(API 23,API 24,API 25,API 26,API 27,API 28)。它也可以在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);

7
为使外观更好看,请使用高度而不是宽度,并取其20%而不是10%。
小白

2
接受的答案有时会导致怪异的缩放。这就像一个魅力。这是一个更好的答案。
侯赛因鹎

1
这个答案比被接受的答案更好,被接受的答案引起一些奇怪的行为。
Haytham

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

1
很好的人,来自Udemy教程来的,他们用您的答案来解决问题。
Shantanu Shady

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

这比OnGlobalLayoutListener花费的时间更长,因此对我来说,在将相机移到我需要的位置之前,它仍然会先显示地图的默认区域/缩放
直到

当我的2个标记与地图边界接触时,如何进行填充。
Pratik Butani

9

对我来说很好。

通过此代码,我在地图屏幕上显示具有特定缩放比例的多个标记。

//声明的变量

private LatLngBounds bounds;
private LatLngBounds.Builder builder;

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

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

    }

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

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

4

注意 -这不是原始问题的解决方案。这是为了讨论的子问题的一种的溶液上方

@andr 澄清2的解决方案-

当边界中只有一个标记时,这确实是有问题的,并且由于该标记,缩放级别被设置为很高的级别(级别21)。Google目前还没有提供任何方法来设置最大缩放级别。当标记多于1个但它们彼此非常接近时,也会发生这种情况。然后,也会出现相同的问题。

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

CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, padding);
mMap.moveCamera(cu);

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

float currentZoom = mMap.getCameraPosition().zoom;

如果此级别大于16(只有在标记数量很少或所有标记彼此都非常接近的情况下才会出现),则只需将缩放级别设置为16,即可在该特定位置缩小地图。

mMap.moveCamera(CameraUpdateFactory.zoomTo(16));

这样,您永远也不会遇到@andr很好解释的“ bizarre”缩放级别的问题。


好的解决方案,但是如果将“ cu”对象放在onMapReady()内,则在这种情况下会有不当行为:接收到的位置->缩放很大,因此将其设置为16->然后用户放大->再次接收到的位置,并且照相机是回到第16级。这可以是在几乎实时接收位置的问题,因为它会回头率16级
马赫纳比尔

“而且Google目前没有提供任何方法来设置最大缩放级别。”-不正确:developers.google.com/android/reference/com/google/android/gms/…–
user1209216

3

这会有所帮助..来自google api演示

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

有关明确的信息,请查看此URL。 https://github.com/googlemaps/android-samples/blob/master/ApiDemos/app/src/main/java/com/example/mapdemo/MarkerDemoActivity.java



1

在Google地图上显示所有标记

在这些方法中,存储所有标记并自动缩放以在Google地图中显示所有标记。

// Declare the Markers List.
List<MarkerOptions> markerList;
private BitmapDescriptor vnrPoint,banPoint;


public void storeAllMarkers()
{
      markerList=new ArrayList<>();
      markerList.removeAll(markerList);


      // latitude and longitude of Virudhunagar

      double latitude1=9.587209;
      double longitude1=77.951431;
   vnrPoint=BitmapDescriptorFactory.fromResource(R.drawable.location_icon_1);
      LatLng vnr = new LatLng(latitude1, longitude1);
      MarkerOptions vnrMarker = new MarkerOptions();
      vnrMarker.position(vnr);
      vnrMarker.icon(vnrPoint);
      markerList.add(vnrMarker);

      // latitude and longitude of Bengaluru

      double latitude2=12.972442;
      double longitude2=77.580643;

    banPoint=BitmapDescriptorFactory.fromResource(R.drawable.location_icon_2);

      LatLng ban = new LatLng(latitude2, longitude2);
      MarkerOptions bengalureMarker = new MarkerOptions();
      bengalureMarker.position(ban);
      bengalureMarker.icon(banPoint);
      markerList.add(bengalureMarker);

      // You can add any numbers of MarkerOptions like this.

     showAllMarkers();

 }


public void showAllMarkers()
{
    LatLngBounds.Builder builder = new LatLngBounds.Builder();

    for (MarkerOptions m : markerList) {
        builder.include(m.getPosition());
    }

    LatLngBounds bounds = builder.build();

    int width = getResources().getDisplayMetrics().widthPixels;
    int height = getResources().getDisplayMetrics().heightPixels;
    int padding = (int) (width * 0.30); 

    // Zoom and animate the google map to show all markers

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

0

使用方法“ getCenterCoordinate”获取中心坐标并在CameraPosition中使用。

private void setUpMap() {
    mMap.setMyLocationEnabled(true);
    mMap.getUiSettings().setScrollGesturesEnabled(true);
    mMap.getUiSettings().setTiltGesturesEnabled(true);
    mMap.getUiSettings().setRotateGesturesEnabled(true);

    clientMarker = mMap.addMarker(new MarkerOptions()
            .position(new LatLng(Double.valueOf(-12.1024174), Double.valueOf(-77.0262274)))
            .icon(BitmapDescriptorFactory.fromResource(R.mipmap.ic_taxi))
    );
    clientMarker = mMap.addMarker(new MarkerOptions()
            .position(new LatLng(Double.valueOf(-12.1024637), Double.valueOf(-77.0242617)))
            .icon(BitmapDescriptorFactory.fromResource(R.mipmap.ic_location))
    );

    camPos = new CameraPosition.Builder()
            .target(getCenterCoordinate())
            .zoom(17)
            .build();
    camUpd3 = CameraUpdateFactory.newCameraPosition(camPos);
    mMap.animateCamera(camUpd3);
}


public LatLng getCenterCoordinate(){
    LatLngBounds.Builder builder = new LatLngBounds.Builder();
    builder.include(new LatLng(Double.valueOf(-12.1024174), Double.valueOf(-77.0262274)));
    builder.include(new LatLng(Double.valueOf(-12.1024637), Double.valueOf(-77.0242617)));
    LatLngBounds bounds = builder.build();
    return bounds.getCenter();
}

0

我还有另一种方法可以使同一件事完美地运行。因此,要在屏幕上显示所有标记,我们需要一个中心纬度和缩放级别。这是一个功能,可以给您双方,并且需要所有标记的Latlng对象作为输入。

 public Pair<LatLng, Integer> getCenterWithZoomLevel(LatLng... l) {
    float max = 0;

    if (l == null || l.length == 0) {
        return null;
    }
    LatLngBounds.Builder b = new LatLngBounds.Builder();
    for (int count = 0; count < l.length; count++) {
        if (l[count] == null) {
            continue;
        }
        b.include(l[count]);
    }

    LatLng center = b.build().getCenter();

    float distance = 0;
    for (int count = 0; count < l.length; count++) {
        if (l[count] == null) {
            continue;
        }
        distance = distance(center, l[count]);
        if (distance > max) {
            max = distance;
        }
    }

    double scale = max / 1000;
    int zoom = ((int) (16 - Math.log(scale) / Math.log(2)));
    return new Pair<LatLng, Integer>(center, zoom);
}

该函数返回可以使用的Pair对象

配对对= getCenterWithZoomLevel(l1,l2,l3 ..); mGoogleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(pair.first,pair.second));

您可以使用-1来调整缩放,而不是使用填充使标记远离屏幕边界。


-3
   //For adding a marker in Google map
        MarkerOptions mp = new MarkerOptions();
        mp.position(new LatLng(Double.parseDouble(latitude), Double.parseDouble(longitude)));
        mp.snippet(strAddress);
        map.addMarker(mp);

        try {

            b = new LatLngBounds.Builder();

            if (MapDetailsList.list != null && MapDetailsList.list.size() > 0) {

                for (int i = 0; i < MapDetailsList.list.size(); i++) {

                    b.include(new LatLng(Double.parseDouble(MapDetailsList.list.get(i).getLatitude()),
                            Double.parseDouble(MapDetailsList.list.get(i).getLongitude())));

                }
                LatLngBounds bounds = b.build();

                DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
                int width = displayMetrics.widthPixels;
                int height = displayMetrics.heightPixels;

                // Change the padding as per needed
                CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, width-200, height-200, 5);
                // map.setCenter(bounds.getCenter());

                map.animateCamera(cu);

            }

        } catch (Exception e) {

        }

http://i64.tinypic.com/2qjybh4.png

http://i63.tinypic.com/flzwus.png

http://i63.tinypic.com/112g5fm.png

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.