Bản đồ Android v2 zoom để hiển thị tất cả các điểm đánh dấu


286

Tôi có 10 điểm trong GoogleMap. Tôi muốn phóng to hết mức có thể và giữ tất cả các điểm đánh dấu? Trong phiên bản trước, điều này có thể đạt được zoomToSpan()nhưng trong v2 tôi không biết làm thế nào để làm điều đó. Hơn nữa, tôi biết bán kính của vòng tròn cần phải được nhìn thấy.

Câu trả lời:


810

Bạn nên sử dụng CameraUpdatelớp để làm (có thể) tất cả các chuyển động bản đồ lập trình.

Để làm điều này, trước tiên hãy tính giới hạn của tất cả các điểm đánh dấu như vậy:

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

Sau đó, có được một đối tượng mô tả chuyển động bằng cách sử dụng nhà máy CameraUpdateFactory::

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

Cuối cùng di chuyển bản đồ:

googleMap.moveCamera(cu);

Hoặc nếu bạn muốn một hình ảnh động:

googleMap.animateCamera(cu);

Đó là tất cả :)

Làm rõ 1

Hầu như tất cả các phương thức di chuyển đều yêu cầu Mapđối tượng phải vượt qua quá trình bố trí. Bạn có thể chờ đợi điều này xảy ra bằng cách sử dụng addOnGlobalLayoutListenercấu trúc. Chi tiết có thể được tìm thấy trong các ý kiến ​​cho câu trả lời này và câu trả lời còn lại. Bạn cũng có thể tìm thấy một mã hoàn chỉnh để thiết lập phạm vi bản đồ bằng cách sử dụng addOnGlobalLayoutListenerở đây .

Làm rõ 2

Một nhận xét lưu ý rằng việc sử dụng phương pháp này chỉ cho một điểm đánh dấu trong thu phóng bản đồ được đặt thành mức thu phóng "kỳ quái" (mà tôi tin là mức thu phóng tối đa có sẵn cho vị trí đã cho). Tôi nghĩ rằng điều này được mong đợi bởi vì:

  1. Các LatLngBounds boundsví dụ sẽ có northeasttài sản tương đương với southwest, có nghĩa là phần diện tích đất được bao phủ bởi đây boundschính là bằng không. (Điều này hợp lý vì một điểm đánh dấu duy nhất không có khu vực.)
  2. Bằng cách chuyển boundscho CameraUpdateFactory.newLatLngBoundsbạn về cơ bản yêu cầu tính toán mức thu phóng như vậy bounds(có diện tích bằng 0) sẽ bao phủ toàn bộ chế độ xem bản đồ.
  3. Bạn thực sự có thể thực hiện tính toán này trên một tờ giấy. Mức thu phóng lý thuyết là câu trả lời là + (vô cực dương). Trong thực tế, Mapđối tượng không hỗ trợ giá trị này để nó được kẹp ở mức tối đa hợp lý hơn được phép cho vị trí đã cho.

Một cách khác để đặt nó: làm thế nào Mapđối tượng có thể biết nên chọn mức thu phóng nào cho một vị trí ? Có thể giá trị tối ưu phải là 20 (nếu nó đại diện cho một địa chỉ cụ thể). Hoặc có thể 11 (nếu nó đại diện cho một thị trấn). Hoặc có thể là 6 (nếu nó đại diện cho một quốc gia). API không thông minh và quyết định là tùy thuộc vào bạn.

Vì vậy, bạn chỉ cần kiểm tra nếu markerschỉ có một vị trí và nếu vậy, hãy sử dụng một trong:

  • CameraUpdate cu = CameraUpdateFactory.newLatLng(marker.getPosition()) - đi đến vị trí đánh dấu, giữ nguyên mức thu phóng hiện tại.
  • CameraUpdate cu = CameraUpdateFactory.newLatLngZoom(marker.getPosition(), 12F) - đi đến vị trí đánh dấu, đặt mức thu phóng thành giá trị được chọn tùy ý 12.

21
Cần lưu ý rằng việc di chuyển không thể xảy ra từ các cuộc gọi onCreate, chế độ xem phải được tạo. Tôi cần sử dụng addOnGlobalLayoutListener để lấy mẫu thích hợp.
Baruch Ngay cả

6
@Bar Vâng, điều này đúng một phần. Nói chính xác: một số phương thức di chuyển sẽ không hoạt động ngay sau khi tạo đối tượng bản đồ. Lý do cho điều này là đối tượng bản đồ chưa được đo, tức là nó chưa trải qua quá trình bố trí. Một sửa chữa điển hình là sử dụng addOnGlobalLayoutListener()hoặc post()với một thích hợp Runnable. Đây chính xác là lý do tại sao không thể thực hiện tọa độ màn hình đánh dấu onCreate- xem stackoverflow.com/q/14429877/1820695 Tuy nhiên, bạn có thể sử dụng một số phương pháp ngay cả trước khi bố cục xảy ra - ví dụ: CameraUpdateFactory.newLatLngBounds()với 4 thông số .
andr

1
Man, bạn tiết kiệm một ngày của tôi ... thực sự đang cố gắng tự mình làm, tính toán giới hạn thủ công và phóng to trong khi điểm đánh dấu trong đó ... hoạt động khá xấu, nhưng với phương pháp đơn giản của bạn, nó hoạt động như một bùa mê. Cảm ơn
Bibu

9
googleMap .setOnMapLoadedCallback (GoogleMap.OnMapLoadedCallback () {@Override void công khai onMapLoaded () {googleMap.moveCamera (cu);}}); Điều này sẽ tránh được các lỗi về biện pháp.
Ramz

1
nó hoạt động khác nhưng khi có một điểm đánh dấu duy nhất trên bản đồ, nó phóng to đến một mức độ kỳ quái nào đó mà bản đồ trở nên mờ đi. Làm thế nào để khắc phục điều này?
Utsav Gupta

124

Bản đồ Google V2

Giải pháp sau đây hoạt động cho Android Marshmallow 6 (API 23, API 24, API 25, API 26, API 27, API 28). Nó cũng hoạt động trong 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
Để có lớp đệm đẹp hơn, hãy sử dụng chiều cao thay vì chiều rộng và lấy 20% thay vì 10%.
noob

2
Câu trả lời được chấp nhận đôi khi gây ra sự phóng to kỳ lạ. Công việc này như một cái duyên vậy. Đây là một câu trả lời tốt hơn.
Hüseyin Bülbül

1
Câu trả lời này hoạt động tốt hơn câu trả lời được chấp nhận, câu trả lời được chấp nhận gây ra một số hành vi mệt mỏi.
Haytham

13

Vì thế

Tôi cần sử dụng addOnGlobalLayoutListener để lấy mẫu thích hợp

ví dụ: Google Map của bạn nằm trong 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
Đến đây từ hướng dẫn của Udemy, người làm việc tuyệt vời, họ đã sử dụng câu trả lời của bạn để giải quyết vấn đề.
Chaianu Shady

13

Tôi không thể sử dụng onGlobalLayoutlistener, vì vậy đây là một giải pháp khác để ngăn chặn "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."lỗi:

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

Cái này mất nhiều thời gian hơn OnGlobalLayoutListener, vì vậy đối với tôi, nó vẫn hiển thị vùng mặc định / thu phóng bản đồ trước, trước khi di chuyển máy ảnh theo nhu cầu của tôi
Đến

Làm thế nào để đưa ra một số phần đệm khi 2 điểm đánh dấu của tôi được chạm với giới hạn bản đồ.
Pratik Butani

9

Làm việc tốt cho tôi.

Từ mã này, tôi đang hiển thị nhiều điểm đánh dấu với thu phóng cụ thể trên màn hình bản đồ.

// Biến khai báo

private LatLngBounds bounds;
private LatLngBounds.Builder builder;

// Phương pháp thêm nhiều điểm đánh dấu bằng biểu tượng có thể vẽ

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

    }

// Để thêm nhiều điểm đánh dấu hiển thị trên bản đồ

@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

Lưu ý - Đây không phải là một giải pháp cho câu hỏi ban đầu. Đây là một giải pháp cho một trong những bài toán con đã thảo luận ở trên .

Giải pháp cho @andr Làm rõ 2 -

Nó thực sự có vấn đề khi chỉ có một điểm đánh dấu trong giới hạn và do nó, mức thu phóng được đặt ở mức rất cao ( cấp 21 ). Và Google không cung cấp bất kỳ cách nào để đặt mức thu phóng tối đa tại thời điểm này. Điều này cũng có thể xảy ra khi có nhiều hơn 1 điểm đánh dấu nhưng tất cả chúng đều khá gần nhau. Sau đó, vấn đề tương tự sẽ xảy ra.

Giải pháp - Giả sử bạn muốn Bản đồ của mình không bao giờ vượt quá mức thu phóng 16. Sau đó, sau khi làm -

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

Kiểm tra xem mức thu phóng của bạn có vượt qua mức 16 (hoặc bất cứ điều gì bạn muốn) -

float currentZoom = mMap.getCameraPosition().zoom;

Và nếu mức này lớn hơn 16, sẽ chỉ là nếu có rất ít điểm đánh dấu hoặc tất cả các điểm đánh dấu rất gần nhau, thì chỉ cần thu nhỏ bản đồ của bạn tại vị trí cụ thể đó chỉ bằng cách đặt mức thu phóng thành 16.

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

Bằng cách này, bạn sẽ không bao giờ gặp phải vấn đề về mức thu phóng "kỳ quái" được giải thích rất tốt bởi @andr.


Giải pháp tốt nhưng nếu bạn đặt đối tượng "cu" bên trong onMapReady (), thì có một hành vi sai trong trường hợp này: vị trí nhận được -> thu phóng lớn, vì vậy hãy đặt nó 16 -> sau đó người dùng sẽ phóng to -> vị trí nhận lại và camera là đưa trở lại cấp 16 . Đây có thể là một vấn đề khi vị trí được nhận gần như theo thời gian thực vì nó sẽ tiếp tục quay trở lại cấp độ 16.
Maher Nabil

"Và Google không cung cấp bất kỳ cách nào để đặt mức thu phóng tối đa tại thời điểm này." - Không đúng: developers.google.com/android/reference/com/google/android/gms/
Kẻ

3

điều này sẽ giúp .. từ 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));
                }
            });
        }
    }

để biết thông tin rõ ràng, hãy nhìn vào url này. https://github.com/googlemaps/android-samples/blob/master/ApiDemos/app/src/main/java/com/example/mapdemo/MarkerDemoActivity.java



1

Hiển thị tất cả các điểm đánh dấu bằng bản đồ Google

Trong các Phương thức này lưu trữ tất cả các Điểm đánh dấu và tự động phóng to để hiển thị tất cả các điểm đánh dấu trong bản đồ 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

Sử dụng phương thức "getCenterCoordine" để lấy tọa độ trung tâm và sử dụng trong CameraPocation.

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

Tôi có một cách khác để làm điều tương tự này hoạt động hoàn hảo. Vì vậy, ý tưởng phía sau để hiển thị tất cả các điểm đánh dấu trên màn hình, chúng ta cần một mức độ trung tâm dài và thu phóng. đây là chức năng sẽ cung cấp cho bạn cả hai và cần tất cả các đối tượng Latlng đánh dấu làm đầu vào.

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

Hàm này trả về đối tượng Cặp mà bạn có thể sử dụng như

Cặp cặp = getCenterWithZoomLevel (l1, l2, l3 ..); mGoogleMap.moveCamera (CameraUpdateFactory.newLatLngZoom (cặp.first, cặp.second));

thay vào đó, bạn có thể thay vì sử dụng phần đệm để tránh các điểm đánh dấu khỏi ranh giới màn hình, bạn có thể điều chỉnh thu phóng theo -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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.