Zoom peta Android v2 untuk menampilkan semua penanda

286

Saya memiliki 10 spidol di GoogleMap. Saya ingin memperbesar sebanyak mungkin dan menjaga agar semua marker terlihat? Pada versi sebelumnya ini dapat dicapai dari zoomToSpan()tetapi di v2 saya tidak tahu bagaimana melakukan itu. Selanjutnya, saya tahu jari-jari lingkaran yang perlu terlihat.

Asanka Senavirathna
sumber

Jawaban:

810

Anda harus menggunakan CameraUpdatekelas untuk melakukan (mungkin) semua gerakan peta terprogram.

Untuk melakukan ini, pertama hitung batas-batas semua penanda seperti:

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

Kemudian dapatkan objek deskripsi gerakan dengan menggunakan pabrik CameraUpdateFactory::

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

Akhirnya pindahkan peta:

googleMap.moveCamera(cu);

Atau jika Anda menginginkan animasi:

googleMap.animateCamera(cu);

Itu saja :)

Klarifikasi 1

Hampir semua metode gerakan membutuhkan Mapobjek yang telah melewati proses tata letak. Anda bisa menunggu ini terjadi menggunakan addOnGlobalLayoutListenerkonstruk. Detail dapat ditemukan dalam komentar untuk jawaban ini dan sisa jawaban. Anda juga dapat menemukan kode lengkap untuk mengatur tingkat peta menggunakan di addOnGlobalLayoutListenersini .

Klarifikasi 2

Satu komentar mencatat bahwa menggunakan metode ini hanya untuk satu penanda menghasilkan zoom peta yang diatur ke tingkat zoom "aneh" (yang saya yakini sebagai tingkat zoom maksimum yang tersedia untuk lokasi tertentu). Saya pikir ini diharapkan karena:

  1. Mesin LatLngBounds boundsvirtual akan memiliki northeastproperti sama dengan southwest, yang berarti bahwa porsi area bumi yang dicakup oleh ini boundspersis nol. (Ini logis karena satu penanda tidak memiliki area.)
  2. Dengan memberikan boundskepada CameraUpdateFactory.newLatLngBoundsAnda pada dasarnya meminta perhitungan tingkat zoom sedemikian rupa sehingga bounds(memiliki area nol) akan mencakup seluruh tampilan peta.
  3. Anda sebenarnya dapat melakukan perhitungan ini pada selembar kertas. Level pembesaran teoritis yang jawabannya adalah + ∞ (positif tak terhingga). Dalam praktiknya, Mapobjek tidak mendukung nilai ini sehingga dijepit ke tingkat maksimum yang lebih masuk akal yang diizinkan untuk lokasi tertentu.

Cara lain untuk menjelaskannya: bagaimana Mapobjek dapat mengetahui level zoom apa yang harus dipilih untuk satu lokasi ? Mungkin nilai optimal harus 20 (jika itu mewakili alamat tertentu). Atau mungkin 11 (jika itu mewakili kota). Atau mungkin 6 (jika itu mewakili negara). API tidak sepintar itu dan keputusannya terserah Anda.

Jadi, Anda cukup memeriksa apakah markershanya memiliki satu lokasi dan jika demikian, gunakan salah satu dari:

  • CameraUpdate cu = CameraUpdateFactory.newLatLng(marker.getPosition()) - pergi ke posisi marker, biarkan level zoom saat ini utuh.
  • CameraUpdate cu = CameraUpdateFactory.newLatLngZoom(marker.getPosition(), 12F) - pergi ke posisi marker, atur level zoom ke nilai yang dipilih secara sewenang-wenang 12.
andr
sumber
21
Perlu dicatat bahwa langkah itu tidak dapat terjadi dari panggilan onCreate, tampilan harus dibuat. Saya perlu menggunakan addOnGlobalLayoutListener untuk mendapatkan sampel yang sesuai.
Baruch Even
6
@ Yah, ini sebagian benar. Tepatnya: beberapa metode gerakan tidak akan berfungsi setelah membuat objek peta. Alasan untuk ini adalah objek peta belum diukur yaitu belum mengalami proses tata letak. Perbaikan khas adalah menggunakan addOnGlobalLayoutListener()atau post()dengan yang sesuai Runnable. Inilah alasan mengapa koordinat layar penanda tidak dapat dilakukan onCreate- lihat stackoverflow.com/q/14429877/1820695 Namun Anda dapat menggunakan beberapa metode bahkan sebelum tata letak terjadi - misalnya. CameraUpdateFactory.newLatLngBounds()dengan 4 params .
andr
1
Man, Anda menyelamatkan hari saya ... sebenarnya mencoba melakukannya sendiri, menghitung batas secara manual, dan memperbesar saat penanda di dalamnya ... bekerja sangat jelek, tetapi dengan metode sederhana Anda, ini bekerja seperti pesona. Terima kasih
Bibu
9
googleMap .setOnMapLoadedCallback (GoogleMap.OnMapLoadedCallback () baru {@Override public void onMapLoaded () {googleMap.moveCamera (cu);}}); Ini akan menghindari kesalahan pada ukuran.
Ramz
1
itu bekerja sebaliknya tetapi ketika ada satu penanda pada peta itu memperbesar ke tingkat aneh bahwa peta menjadi kabur. Bagaimana cara memperbaikinya?
Utsav Gupta
124

Google Map V2

Solusi berikut ini berfungsi untuk Android Marshmallow 6 (API 23, API 24, API 25, API 26, API 27, API 28). Ini juga berfungsi di 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);
Zumry Mohamed
sumber
7
Untuk lapisan yang terlihat lebih baik, gunakan ketinggian daripada lebar dan ambil 20%, bukan 10%.
noob
2
Jawaban yang diterima terkadang menyebabkan zoom aneh. Ini bekerja seperti pesona. Ini jawaban yang lebih baik.
Hüseyin Bülbül
1
Jawaban ini bekerja lebih baik daripada yang diterima, yang diterima menyebabkan beberapa perilaku aneh.
Haytham
13

Begitu

Saya perlu menggunakan addOnGlobalLayoutListener untuk mendapatkan sampel yang sesuai

misalnya, Google Map Anda ada di dalam 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
        }
    });
Eugene Voronoy
sumber
1
Datang ke sini dari tutorial Udemy, pekerja hebat, mereka menggunakan jawaban Anda untuk menyelesaikan masalah.
Shantanu Shady
13

Saya tidak bisa menggunakan onGlobalLayoutlistener, jadi di sini ada solusi lain untuk mencegah "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."kesalahan:

mMap.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() { 
@Override 
public void onMapLoaded() { 
    mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(builder.build(), 15));
 } 
});
chrjs
sumber
Yang ini membutuhkan waktu lebih lama daripada OnGlobalLayoutListener, jadi bagi saya ini masih menunjukkan area default peta / zoom dulu, sebelum memindahkan kamera ke kebutuhan saya
Hingga
Cara memberi padding karena 2 marker saya disentuh dengan batas peta.
Pratik Butani
9

Bekerja dengan baik untukku.

Dari kode ini, saya menampilkan beberapa penanda dengan zoom khusus pada layar peta.

// Variabel yang dideklarasikan

private LatLngBounds bounds;
private LatLngBounds.Builder builder;

// Metode untuk menambahkan beberapa titik penanda dengan ikon yang dapat digambar

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

    }

// Untuk menambahkan beberapa penanda yang terlihat di peta

@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);
BK19
sumber
4

Catatan - Ini bukan solusi untuk pertanyaan awal. Ini adalah solusi untuk salah satu submasalah yang dibahas di atas .

Solusi untuk @andr Klarifikasi 2 -

Ini benar-benar bermasalah ketika hanya ada satu penanda di batas dan karenanya tingkat zoom diatur ke tingkat yang sangat tinggi ( level 21 ). Dan Google tidak menyediakan cara untuk mengatur tingkat zoom maks pada saat ini. Ini juga bisa terjadi ketika ada lebih dari 1 penanda tetapi semuanya cukup dekat satu sama lain. Kemudian masalah yang sama akan terjadi.

Solusi - Misalkan Anda ingin Peta Anda tidak pernah melampaui tingkat zoom 16. Lalu setelah melakukan -

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

Periksa apakah level zoom Anda telah melewati level 16 (atau apa pun yang Anda inginkan) -

float currentZoom = mMap.getCameraPosition().zoom;

Dan jika level ini lebih besar dari 16, yang hanya akan terjadi jika ada marka yang sangat sedikit atau semua marka sangat dekat satu sama lain, maka perkecil peta Anda pada posisi tertentu hanya dengan mengatur level zoom ke 16.

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

Dengan cara ini Anda tidak akan pernah memiliki masalah tingkat zoom "aneh" yang dijelaskan dengan sangat baik oleh @andr juga.

Jyotman Singh
sumber
solusi yang bagus tetapi jika Anda memasukkan objek "cu" ke dalam onMapReady (), maka ada kesalahan dalam hal ini: lokasi diterima -> zoom besar jadi buat 16 -> lalu pengguna memperbesar -> lokasi diterima lagi dan kamera diterima kembalikan ke level 16 . Ini bisa menjadi masalah ketika lokasi diterima hampir secara real-time karena akan terus kembali ke level 16.
Maher Nabil
"Dan Google tidak menyediakan cara untuk mengatur tingkat zoom maks pada saat ini." - Tidak benar: developers.google.com/android/reference/com/google/android/gms/…
user1209216
3

ini akan membantu .. dari demo google apis

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

untuk info lebih jelas lihat url ini. https://github.com/googlemaps/android-samples/blob/master/ApiDemos/app/src/main/java/com/example/mapdemo/MarkerDemoActivity.java

Amit Tumkur
sumber
1

Tampilkan Semua Penanda dengan peta Google

Dalam Metode ini, simpan semua Penanda dan perbesar secara otomatis untuk menampilkan semua penanda di google map.

// 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);
}
Sathish kumar TM
sumber
0

Gunakan metode "getCenterCoordinate" untuk mendapatkan koordinat pusat dan digunakan di 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();
}
Jonathan Nolasco Barrientos
sumber
0

Saya punya satu cara lain untuk melakukan hal yang sama ini bekerja dengan sempurna. jadi ide di belakang untuk menunjukkan semua spidol di layar kita membutuhkan pusat lat panjang dan tingkat zoom. di sini adalah fungsi yang akan memberi Anda berdua dan membutuhkan objek Latlng semua penanda sebagai input.

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

Fungsi ini mengembalikan objek Pair yang dapat Anda gunakan sukai

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

Anda bisa daripada menggunakan pelapis untuk menjauhkan spidol dari batas layar, Anda dapat menyesuaikan zoom dengan -1.

Anuj Jindal
sumber
-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

PeddiRaju
sumber