220

Ho 10 marcatori nel GoogleMap. Voglio ingrandire il più possibile e mantenere tutti i marcatori in vista? Nella versione precedente questo può essere ottenuto da zoomToSpan() ma in v2 non ho idea di come farlo. Inoltre, conosco il raggio del cerchio che deve essere visibile.Mappa Android zoom v2 per mostrare tutti i marcatori

+1

La mia risposta ti fornirà una soluzione più semplice per le ultime apis Android. http://stackoverflow.com/a/38013331/1348522 –

risposta

660

È necessario utilizzare la classe CameraUpdate per eseguire (probabilmente) tutti i movimenti di mappa programmatici.

Per fare questo, prima di calcolare i limiti di tutti i marcatori 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); 

spostare Infine la mappa :

googleMap.moveCamera(cu); 

Oppure se si desidera un'animazione:

googleMap.animateCamera(cu); 

Questo è tutto :)

Chiarificazione 1

Quasi tutti i metodi richiedono movimento dell'oggetto Map aver superato il processo di layout. È possibile attendere che ciò accada utilizzando il costrutto addOnGlobalLayoutListener. Dettagli possono essere trovati nei commenti a questa risposta e alle restanti risposte. È inoltre possibile trovare un complete code for setting map extent using addOnGlobalLayoutListener here.

Chiarimento 2

Un commento fa notare che l'utilizzo di questo metodo per un solo risultati marcatori nella cartina set zoom ad un livello di zoom "bizzarro" (che credo di essere il massimo livello di zoom disponibili per determinato luogo). Credo che questo è previsto perché:

  1. L'istanza LatLngBounds bounds avrà northeast struttura uguale a southwest, significa che la porzione della superficie della terra oggetto della presente bounds è esattamente uguale a zero. (Questo è logico poiché un singolo marcatore non ha area.)
  2. Passando da bounds a CameraUpdateFactory.newLatLngBounds, si richiede essenzialmente un calcolo di tale livello di zoom che bounds (con area zero) coprirà l'intera visualizzazione della mappa.
  3. È possibile eseguire questo calcolo su un foglio di carta. Il livello di zoom teorico che è la risposta è + ∞ (infinito positivo). In pratica l'oggetto Map non supporta questo valore, quindi è bloccato a un livello massimo più ragionevole consentito per una determinata posizione.

Un altro modo per dirla: come può Map oggetto sapere quale livello di zoom dovrebbe optare per un unico luogo? 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, si dovrebbe semplicemente controllare se markers ha una sola posizione e, in caso affermativo, utilizzare uno dei:

  • CameraUpdate cu = CameraUpdateFactory.newLatLng(marker.getPosition()) - andare a posizione del marker, lasciare intatto il livello di zoom corrente.
  • CameraUpdate cu = CameraUpdateFactory.newLatLngZoom(marker.getPosition(), 12F) - andare a posizione del marker, insieme al livello di zoom scelto arbitrariamente il valore 12.
+19

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. –

+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 della mappa non è stato * misurato * eppure non ha subito il processo di layout. Una tipica soluzione è usare 'addOnGlobalLayoutListener()' o 'post()' con un appropriato 'Runnable'. Questo è esattamente il motivo per cui non è possibile ottenere coordinate dello schermo dell'indicatore in 'onCreate' - vedere http://stackoverflow.com/q/14429877/1820695 Tuttavia * è possibile * utilizzare alcuni metodi anche prima che il layout sia successo, ad es. 'CameraUpdateFactory.newLatLngBounds()' con * 4 parametri *. – andr

+1

Uomo, mi hai salvato la giornata ... stavo davvero provando a farlo da solo, calcola i limiti manualmente, e lo zoom mentre il marcatore è in esso ... stava lavorando molto brutto, ma con il tuo metodo semplice, funziona come un incantesimo . Grazie – Bibu

11

Così

I needed to use addOnGlobalLayoutListener to get the appropriate sample

ad esempio, Google Map è all'interno 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 
     } 
    }); 
11

Non potrei usare il onGlobalLayoutlistener, quindi ecco un'altra soluzione per prevenire l'errore "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)); 
} 
}); 
+0

Questo richiede molto più tempo di OnGlobalLayoutListener, quindi per me ha comunque mostrato il mappa prima l'area predefinita/zoom, prima di spostare la fotocamera secondo le mie esigenze – Till

0

Utilizzare il metodo "getCenterCoordinate" per ottenere la coordinata centrale e utilizzarla 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(); 
} 
-2
//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

2

Nota - Questa non è una soluzione alla domanda iniziale. Questa è una soluzione a uno dei sottoproblemi discussi above.

soluzione per @andr Chiarimento 2 -

sua davvero problematico quando c'è un solo marcatore nei limiti ed a causa di essa il livello di zoom è impostato su un livello molto elevato (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 segnalino, ma sono tutti abbastanza vicini l'uno all'altro. Quindi si verificherà anche lo stesso problema.

Soluzione - Supponiamo che si desideri che la mappa non superi mai il livello di zoom 16. Poi, dopo aver fatto -

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

Verificare che il livello di zoom ha attraversato il livello 16 (o quello che volete) -

float currentZoom = mMap.getCameraPosition().zoom; 

E se questo livello è maggiore di 16, che sarà solo in caso di sono molto meno marcatori o tutti gli indicatori sono molto vicini gli uni agli altri, quindi è sufficiente diminuire la vostra mappa in quella particolare posizione solo dal seting il livello di zoom a 16.

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

in questo modo non dovrete mai la p roblema del livello di zoom "bizzarro" spiegato molto bene anche da @andr.

+0

buona soluzione ma se metti l'oggetto "cu" dentro onMapReady(), allora c'è un comportamento scorretto in questo caso: ** posizione ricevuta -> lo zoom è grande quindi fai it 16 -> quindi l'utente esegue lo zoom in -> posizione nuovamente ricevuta e la telecamera torna al livello 16 **. Questo può essere un problema quando la posizione viene ricevuta quasi in tempo reale poiché continuerà a tornare al livello 16. –

+0

"E Google non fornisce alcun modo per impostare il livello massimo di zoom a questo punto." - Non vero: https : //developers.google.com/android/reference/com/google/android/gms/maps/GoogleMap.html#setMaxZoomPreference (float) – user1209216

1

questo aiuterebbe ..da google apis demo

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 indirizzo. https://github.com/googlemaps/android-samples/blob/master/ApiDemos/app/src/main/java/com/example/mapdemo/MarkerDemoActivity.java

52

Google Map V2: MarkerOptions Zoom entro i limiti migliore soluzione di lavoro per Android Marshmallow 6 (API 23, API 24, API 25), così, lavori in Xamarin anche

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); 
+0

thank you man :) –

+1

Per un aspetto più bello del padding, usa l'altezza invece della larghezza e prendere il 20% invece del 10% di esso. – noob

+0

Bello, funziona anche su Xamarin! – JMK

3

Working fine for me.

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

variabili // dichiarati

private LatLngBounds bounds; 
private LatLngBounds.Builder builder; 

// metodo per aggiungere più punti di marcatori con l'icona drawable

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 l'aggiunta di più marcatori visibile 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); 
0

I ha avuto un problema simile, utilizzando il seguente codice risolto il problema:

CameraUpdateFactory.newLatLngBounds(bounds, 200, 200, 5) generalmente le differenze di località nel mio caso non sono più di due città vicine.

zoom to fit all markers on map google maps v2

0

ho un altro modo per fare la stessa cosa funziona perfettamente. quindi l'idea alla base di mostrare tutti i marcatori sullo schermo abbiamo bisogno di un centro lat lungo e il livello di zoom. ecco la funzione che ti darà entrambi e avrà bisogno di tutti gli oggetti Latlng di un marker 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); 
} 

Questo oggetto paio di ritorno funzione che è possibile utilizzare come

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

è possibile invece di utilizzare imbottitura per tenere lontano i tuoi marcatori da limiti dello schermo, è possibile regolare lo zoom per -1.