Zoom mappa Android v2 per mostrare tutti gli indicatori


Risposte:


810

Dovresti usare la CameraUpdateclasse per fare (probabilmente) tutti i movimenti della mappa programmatica.

Per fare ciò, prima calcola i limiti di tutti i marker in questo modo:

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

Quindi ottenere un oggetto descrizione del movimento utilizzando la fabbrica CameraUpdateFactory::

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

Infine sposta la mappa:

googleMap.moveCamera(cu);

O se vuoi un'animazione:

googleMap.animateCamera(cu);

È tutto :)

Chiarimento 1

Quasi tutti i metodi di movimento richiedono che l' Mapoggetto abbia superato il processo di layout. Puoi aspettare che ciò accada usando il addOnGlobalLayoutListenercostrutto. I dettagli sono disponibili nei commenti a questa risposta e nelle risposte rimanenti. Puoi anche trovare un codice completo per impostare l'estensione della mappa usando addOnGlobalLayoutListenerqui .

Chiarimento 2

Un commento osserva che l'utilizzo di questo metodo per un solo marker comporta lo zoom della mappa impostato su un livello di zoom "bizzarro" (che credo sia il massimo livello di zoom disponibile per una determinata posizione). Penso che ciò sia previsto perché:

  1. L' LatLngBounds boundsistanza avrà northeastproprietà pari a southwest, il che significa che la porzione di area della terra coperta da questo boundsè esattamente zero. (Questo è logico poiché un singolo marker non ha area.)
  2. Passando boundsa CameraUpdateFactory.newLatLngBoundste essenzialmente richiedi un calcolo di tale livello di zoom che bounds(avendo area zero) coprirà l'intera vista della mappa.
  3. Puoi effettivamente eseguire questo calcolo su un pezzo di carta. Il livello di zoom teorico che è la risposta è + ∞ (infinito positivo). In pratica, l' Mapoggetto non supporta questo valore, quindi viene bloccato a un livello massimo più ragionevole consentito per una determinata posizione.

Un altro modo per dirlo: come può l' Mapoggetto sapere quale livello di zoom dovrebbe scegliere per una singola posizione ? Forse il valore ottimale dovrebbe essere 20 (se rappresenta un indirizzo specifico). O forse 11 (se rappresenta una città). O forse 6 (se rappresenta un paese). L'API non è così intelligente e la decisione spetta a te.

Quindi, dovresti semplicemente controllare se markersha solo una posizione e, in tal caso, utilizzare uno di:

  • CameraUpdate cu = CameraUpdateFactory.newLatLng(marker.getPosition()) - vai alla posizione del marker, lascia intatto il livello di zoom corrente.
  • CameraUpdate cu = CameraUpdateFactory.newLatLngZoom(marker.getPosition(), 12F) - vai alla posizione del marker, imposta il livello di zoom sul valore scelto arbitrariamente 12.

21
Va notato che lo spostamento non può avvenire dalle chiamate onCreate, la vista deve essere creata. Avevo bisogno di usare addOnGlobalLayoutListener per ottenere il campione appropriato.
Baruch Anche

6
@Bar Bene, questo è in parte vero. Per essere precisi: alcuni metodi di movimento non funzioneranno subito dopo aver creato l'oggetto mappa. La ragione di ciò è che l'oggetto mappa non è stato ancora misurato, ovvero non ha subito il processo di layout. Una correzione tipica è quella di utilizzare addOnGlobalLayoutListener()o post()con un appropriato Runnable. Questo è esattamente il motivo per cui non è possibile ottenere le coordinate dello schermo dell'indicatoreonCreate - consultare stackoverflow.com/q/14429877/1820695 Tuttavia, è possibile utilizzare alcuni metodi anche prima che si verifichi il layout, ad es. CameraUpdateFactory.newLatLngBounds()con 4 parametri .
andr

1
Amico, mi salvi la giornata ... in realtà stavo cercando di farlo da solo, calcolare i limiti manualmente e lo zoom mentre il marker è dentro ... stava funzionando abbastanza brutto, ma con il tuo metodo semplice, funziona come un fascino. Grazie
Bibu

9
googleMap .setOnMapLoadedCallback (nuovo GoogleMap.OnMapLoadedCallback () {@Override public void onMapLoaded () {googleMap.moveCamera (cu);}}); Ciò eviterà l'errore sulla misura.
Ramz,

1
funziona altrimenti, ma quando c'è un singolo marker sulla mappa ingrandisce a un livello bizzarro che la mappa diventa sfocata. Come risolvere questo?
Utsav Gupta,

124

Google Map V2

La seguente soluzione funziona per Android Marshmallow 6 (API 23, API 24, API 25, API 26, API 27, API 28). Funziona anche in 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
Per un'imbottitura più bella, usa l'altezza invece della larghezza e prendi il 20% invece del 10% di esso.
Noob,

2
La risposta accettata a volte causa uno zoom strano. Funziona come un fascino. Questa è una risposta migliore
Hüseyin Bülbül,

1
Questa risposta funziona meglio di quella accettata, quella accettata provoca un comportamento weired.
Haytham,

13

Così

Avevo bisogno di usare addOnGlobalLayoutListener per ottenere il campione appropriato

ad esempio, la tua Google Map è all'interno di 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
Sono venuto qui dal tutorial di Udemy, ottimo lavoro, hanno usato la tua risposta per risolvere il problema.
Shantanu Shady,

13

Non ho potuto usare onGlobalLayoutlistener, quindi ecco un'altra soluzione per prevenire l' "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."errore:

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

Questo richiede molto più tempo di OnGlobalLayoutListener, quindi per me mostrava ancora l'area / zoom predefiniti delle mappe, prima di spostare la fotocamera secondo le mie esigenze
Fino al

Come dare un po 'di riempimento quando i miei 2 marcatori vengono toccati con i limiti della mappa.
Pratik Butani,

9

Funziona bene per me.

Da questo codice, sto visualizzando più marcatori con particolare zoom sulla schermata della mappa.

// Variabili dichiarate

private LatLngBounds bounds;
private LatLngBounds.Builder builder;

// Metodo per aggiungere più punti marker con un'icona disegnabile

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

    }

// Per aggiungere più marcatori visibili sulla mappa

@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

Nota : questa non è una soluzione alla domanda originale. Questa è una soluzione a uno dei sottoproblemi discussi sopra .

Soluzione a @andr Clarification 2 -

È davvero problematico quando c'è un solo marker nei limiti e per questo il livello di zoom è impostato su un livello molto alto ( livello 21 ). E Google non fornisce alcun modo per impostare il livello di zoom massimo a questo punto. Questo può accadere anche quando ci sono più di 1 marker ma sono tutti abbastanza vicini l'uno all'altro. Quindi si verificherà anche lo stesso problema.

Soluzione : supponiamo che la tua mappa non superi mai i 16 livelli di zoom. Quindi dopo aver fatto -

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

Controlla se il tuo livello di zoom ha superato il livello 16 (o qualunque cosa tu voglia) -

float currentZoom = mMap.getCameraPosition().zoom;

E se questo livello è maggiore di 16, che sarà solo se ci sono molti meno marcatori o tutti i marcatori sono molto vicini l'uno all'altro, è sufficiente rimpicciolire la mappa in quella particolare posizione solo impostando il livello di zoom su 16.

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

In questo modo non avrai mai il problema del livello di zoom "bizzarro" spiegato molto bene anche da @andr.


buona soluzione ma se si inserisce l'oggetto "cu" all'interno di onMapReady (), in questo caso si verifica un comportamento errato: la posizione ricevuta -> lo zoom è grande, quindi impostarlo 16 -> quindi l'utente ingrandisce -> la posizione ricevuta di nuovo e la telecamera è rimettere al livello 16 . Questo può essere un problema quando la posizione viene ricevuta quasi in tempo reale poiché continuerà a tornare al livello 16.
Maher Nabil

"E Google non fornisce alcun modo per impostare il livello di zoom massimo a questo punto." - Non è vero: developers.google.com/android/reference/com/google/android/gms/…
user1209216

3

questo aiuterebbe .. dalle demo di 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));
                }
            });
        }
    }

per informazioni chiare guarda questo URL. https://github.com/googlemaps/android-samples/blob/master/ApiDemos/app/src/main/java/com/example/mapdemo/MarkerDemoActivity.java



1

Mostra tutti gli indicatori con la mappa di Google

In questi metodi memorizzare tutti i marker e ingrandire automaticamente per mostrare tutti i marker in 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);
}

0

Utilizzare il metodo "getCenterCoordinate" per ottenere la coordinata centrale e utilizzare in 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

Ho un altro modo per fare che la stessa cosa funzioni perfettamente. quindi l'idea alla base di mostrare tutti i marcatori sullo schermo abbiamo bisogno di un centro lat long e livello di zoom. ecco la funzione che ti darà entrambi e che necessitano di tutti gli oggetti Latlng del marcatore come 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);
}

Questa funzione restituisce l'oggetto Pair che puoi usare come

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

puoi invece di usare il padding per tenere lontano i tuoi marker dai confini dello schermo, puoi regolare lo zoom di -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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.