Android Map v2 Zoom, um alle Markierungen anzuzeigen

286

Ich habe 10 Marker in der GoogleMap. Ich möchte so weit wie möglich zoomen und alle Markierungen im Blick behalten. In der früheren Version kann dies erreicht werden, zoomToSpan()aber in Version 2 habe ich keine Ahnung, wie das geht. Außerdem kenne ich den Radius des Kreises, der sichtbar sein muss.

Asanka Senavirathna
quelle

Antworten:

810

Sie sollten die verwenden CameraUpdate Klasse verwenden, um (wahrscheinlich) alle programmatischen Kartenbewegungen auszuführen.

Berechnen Sie dazu zunächst die Grenzen aller Marker wie folgt:

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

Erhalten Sie dann ein Bewegungsbeschreibungsobjekt, indem Sie die Fabrik verwenden CameraUpdateFactory::

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

Verschieben Sie zum Schluss die Karte:

googleMap.moveCamera(cu);

Oder wenn Sie eine Animation möchten:

googleMap.animateCamera(cu);

Das ist alles :)

Klarstellung 1

Bei fast allen Bewegungsmethoden muss das MapObjekt den Layoutprozess bestanden haben. Sie können mit dem addOnGlobalLayoutListenerKonstrukt darauf warten . Details finden Sie in den Kommentaren zu dieser Antwort und den verbleibenden Antworten. Sie können auch einen finden vollständigen Code für die Einstellung der Kartenausdehnung mit addOnGlobalLayoutListenerhier .

Klarstellung 2

In einem Kommentar wird darauf hingewiesen, dass die Verwendung dieser Methode für nur eine Markierung dazu führt, dass der Kartenzoom auf eine "bizarre" Zoomstufe eingestellt wird (die meiner Meinung nach die maximale Zoomstufe ist, die für einen bestimmten Ort verfügbar ist). Ich denke, das wird erwartet, weil:

  1. Die LatLngBounds boundsInstanz hat eine northeastEigenschaft gleich southwest, was bedeutet, dass der Teil der Erdfläche, der davon bedeckt boundsist, genau Null ist. (Dies ist logisch, da ein einzelner Marker keinen Bereich hat.)
  2. Wenn Sie boundsan CameraUpdateFactory.newLatLngBoundsSie übergeben, fordern Sie im Wesentlichen eine Berechnung einer solchen Zoomstufe an, die bounds(mit einer Fläche von Null) die gesamte Kartenansicht abdeckt.
  3. Sie können diese Berechnung tatsächlich auf einem Blatt Papier durchführen. Die theoretische Zoomstufe, die die Antwort ist, ist + ∞ (positive Unendlichkeit). In der Praxis unterstützt das MapObjekt diesen Wert nicht, sodass es auf ein vernünftigeres maximales Niveau geklemmt wird, das für einen bestimmten Standort zulässig ist.

Anders ausgedrückt: Wie kann das MapObjekt wissen, welche Zoomstufe es für einen einzelnen Standort wählen soll ? Möglicherweise sollte der optimale Wert 20 sein (wenn er eine bestimmte Adresse darstellt). Oder vielleicht 11 (wenn es eine Stadt darstellt). Oder vielleicht 6 (wenn es ein Land darstellt). API ist nicht so klug und die Entscheidung liegt bei Ihnen.

Sie sollten also einfach überprüfen, ob markersnur ein Standort vorhanden ist, und in diesem Fall einen der folgenden Standorte verwenden:

  • CameraUpdate cu = CameraUpdateFactory.newLatLng(marker.getPosition()) - Gehen Sie zur Markierungsposition und lassen Sie die aktuelle Zoomstufe intakt.
  • CameraUpdate cu = CameraUpdateFactory.newLatLngZoom(marker.getPosition(), 12F) - Gehen Sie zur Markierungsposition und stellen Sie die Zoomstufe auf den willkürlich gewählten Wert 12 ein.
andr
quelle
21
Es ist zu beachten, dass die Verschiebung nicht über die onCreate-Aufrufe erfolgen kann. Die Ansicht muss erstellt werden. Ich musste addOnGlobalLayoutListener verwenden, um das entsprechende Beispiel zu erhalten.
Baruch sogar
6
@ Bar Nun, das ist teilweise wahr. Um genau zu sein: Einige Bewegungsmethoden funktionieren nicht direkt nach dem Erstellen des Kartenobjekts. Der Grund dafür ist, dass das Kartenobjekt noch nicht gemessen wurde, dh es wurde nicht dem Layoutprozess unterzogen. Ein typischer Fix ist die Verwendung addOnGlobalLayoutListener()oder post()mit einem geeignetenRunnable . Dies ist genau der Grund, warum das Abrufen von Markierungsbildschirmkoordinaten nicht möglich ist onCreate- siehe stackoverflow.com/q/14429877/1820695. Sie können jedoch einige Methoden verwenden, noch bevor das Layout erstellt wurde - z. CameraUpdateFactory.newLatLngBounds()mit 4 params .
andr
1
Mann, du rettest meinen Tag ... habe tatsächlich versucht, es selbst zu tun, manuelle Grenzen zu berechnen und zu zoomen, während der Marker darin ist ... hat ziemlich hässlich funktioniert, aber mit deiner einfachen Methode funktioniert es wie ein Zauber. Danke
Bibu
9
googleMap .setOnMapLoadedCallback (neues GoogleMap.OnMapLoadedCallback () {@Override public void onMapLoaded () {googleMap.moveCamera (cu);}}); Dadurch wird der Messfehler vermieden.
Ramz
1
es funktioniert anders, aber wenn es eine einzelne Markierung auf der Karte gibt, zoomt es auf eine bizarre Ebene, auf der die Karte unscharf wird. Wie kann ich das beheben?
Utsav Gupta
124

Google Map V2

Die folgende Lösung funktioniert für Android Marshmallow 6 (API 23, API 24, API 25, API 26, API 27, API 28). Es funktioniert auch 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);
Zumry Mohamed
quelle
7
Verwenden Sie für eine bessere Polsterung die Höhe anstelle der Breite und 20% anstelle von 10%.
Noob
2
Akzeptierte Antworten verursachen manchmal seltsames Zoomen. Das funktioniert wie ein Zauber. Dies ist eine bessere Antwort.
Hüseyin Bülbül
1
Diese Antwort funktioniert besser als die akzeptierte, die akzeptierte verursacht ein unerwünschtes Verhalten.
Haytham
13

Damit

Ich musste addOnGlobalLayoutListener verwenden, um das entsprechende Beispiel zu erhalten

Ihre Google Map befindet sich beispielsweise in 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
quelle
1
Kam aus dem Udemy-Tutorial hierher, großartiger Arbeiter, sie haben Ihre Antwort verwendet, um das Problem zu lösen.
Shantanu Shady
13

Ich konnte den onGlobalLayoutlistener nicht verwenden, daher hier eine andere Lösung, um den "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."Fehler zu verhindern :

mMap.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() { 
@Override 
public void onMapLoaded() { 
    mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(builder.build(), 15));
 } 
});
chrjs
quelle
Dieser dauert viel länger als der OnGlobalLayoutListener, daher wurde für mich immer noch zuerst der Standardbereich / Zoom der Karte angezeigt, bevor die Kamera an meine Bedürfnisse angepasst wurde
bis zum
Wie man etwas Polsterung gibt, wenn meine 2 Markierungen mit Kartengrenzen berührt werden.
Pratik Butani
9

Funktioniert gut für mich.

Von diesem Code aus zeige ich mehrere Markierungen mit besonderem Zoom auf dem Kartenbildschirm an.

// Deklarierte Variablen

private LatLngBounds bounds;
private LatLngBounds.Builder builder;

// Methode zum Hinzufügen mehrerer Markierungspunkte mit zeichnbarem Symbol

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

    }

// Zum Hinzufügen mehrerer auf der Karte sichtbarer Markierungen

@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
quelle
4

Hinweis - Dies ist keine Lösung für die ursprüngliche Frage. Dies ist eine Lösung für eines der oben diskutierten Teilprobleme .

Lösung zu @andr Klarstellung 2 -

Es ist wirklich problematisch, wenn sich nur eine Markierung in den Grenzen befindet und die Zoomstufe daher auf eine sehr hohe Stufe eingestellt ist ( Stufe 21 ). Und Google bietet derzeit keine Möglichkeit, die maximale Zoomstufe festzulegen. Dies kann auch passieren, wenn mehr als ein Marker vorhanden ist, diese jedoch alle ziemlich nahe beieinander liegen. Dann tritt auch das gleiche Problem auf.

Lösung - Angenommen, Ihre Karte soll niemals über die Zoomstufe 16 hinausgehen. Dann nach -

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

Überprüfen Sie, ob Ihre Zoomstufe die Stufe 16 überschritten hat (oder was auch immer Sie wollen) -

float currentZoom = mMap.getCameraPosition().zoom;

Und wenn diese Stufe größer als 16 ist, was nur der Fall ist, wenn weniger Markierungen vorhanden sind oder alle Markierungen sehr nahe beieinander liegen, verkleinern Sie Ihre Karte einfach an dieser bestimmten Position, indem Sie die Zoomstufe auf 16 einstellen.

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

Auf diese Weise haben Sie nie das Problem der "bizarren" Zoomstufe, das auch von @andr sehr gut erklärt wird.

Jyotman Singh
quelle
Gute Lösung, aber wenn Sie ein "cu" -Objekt in onMapReady () einfügen, liegt in diesem Fall ein Fehlverhalten vor: Empfangene Position -> Zoom ist groß, machen Sie es 16 -> dann zoomt der Benutzer hinein -> Empfangene Position erneut und Kamera ist auf Level 16 zurücksetzen . Dies kann ein Problem sein, wenn der Standort fast in Echtzeit empfangen wird, da er immer wieder auf Stufe 16 zurückkehrt.
Maher Nabil
"Und Google bietet
derzeit
3

Dies würde helfen .. von 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));
                }
            });
        }
    }

Für klare Informationen schauen Sie sich diese URL an. https://github.com/googlemaps/android-samples/blob/master/ApiDemos/app/src/main/java/com/example/mapdemo/MarkerDemoActivity.java

Amit Tumkur
quelle
1

Ich hatte ein ähnliches Problem. Die Verwendung des folgenden Codes löste das Problem:

CameraUpdateFactory.newLatLngBounds(bounds, 200, 200, 5) Im Allgemeinen sind die Standortunterschiede in meinem Fall nicht mehr als zwei Nachbarstädte.

zoomen, um alle Markierungen auf der Karte Google Maps v2 anzupassen

Avishkar Ramjeet
quelle
1

Alle Marker mit Google Map anzeigen

Speichern Sie in diesen Methoden alle Markierungen und zoomen Sie automatisch, um alle Markierungen in Google Map anzuzeigen.

// 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
quelle
0

Verwenden Sie die Methode "getCenterCoordinate", um die Mittelkoordinate abzurufen und in CameraPosition zu verwenden.

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
quelle
0

Ich habe eine andere Möglichkeit, dasselbe zu tun, funktioniert perfekt. Um alle Markierungen auf dem Bildschirm anzuzeigen, benötigen wir eine mittlere Lat-Länge und eine Zoomstufe. Hier ist die Funktion, die Ihnen beides bietet und alle Latlng-Objekte des Markers als Eingabe benötigt.

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

Diese Funktion gibt ein Pair-Objekt zurück, das Sie wie verwenden können

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

Anstatt Polster zu verwenden, um Ihre Markierungen von Bildschirmgrenzen fernzuhalten, können Sie den Zoom um -1 anpassen.

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