Mapa de Android v2 zoom para mostrar todos los marcadores

286

Tengo 10 marcadores en el GoogleMap. Quiero acercarme lo más posible y mantener todos los marcadores a la vista En la versión anterior, esto se puede lograr, zoomToSpan()pero en v2 no tengo idea de cómo hacerlo. Además, sé el radio del círculo que debe ser visible.

Asanka Senavirathna
fuente

Respuestas:

810

Debería usar la CameraUpdateclase para hacer (probablemente) todos los movimientos programáticos del mapa.

Para hacer esto, primero calcule los límites de todos los marcadores así:

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

Luego obtenga un objeto de descripción de movimiento utilizando la fábrica CameraUpdateFactory:

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

Finalmente mueve el mapa:

googleMap.moveCamera(cu);

O si quieres una animación:

googleMap.animateCamera(cu);

Eso es todo :)

Aclaracion 1

Casi todos los métodos de movimiento requieren que el Mapobjeto haya pasado el proceso de diseño. Puedes esperar a que esto suceda usando la addOnGlobalLayoutListenerconstrucción. Se pueden encontrar detalles en los comentarios a esta respuesta y en las respuestas restantes. También puede encontrar un código completo para configurar la extensión del mapa addOnGlobalLayoutListeneraquí .

Aclaracion 2

Un comentario señala que el uso de este método solo para un marcador da como resultado un zoom de mapa establecido en un nivel de zoom "extraño" (que creo que es el nivel de zoom máximo disponible para una ubicación determinada). Creo que esto se espera porque:

  1. La LatLngBounds boundsinstancia tendrá una northeastpropiedad igual a southwest, lo que significa que la porción del área de la tierra cubierta por esto boundses exactamente cero. (Esto es lógico ya que un solo marcador no tiene área).
  2. Al hacer pasar boundsa CameraUpdateFactory.newLatLngBoundsusted solicita esencialmente un cálculo de tal nivel que un zoom bounds(que tiene un área de cero) cubrirá toda la vista del mapa.
  3. Realmente puede realizar este cálculo en una hoja de papel. El nivel de zoom teórico que es la respuesta es + ∞ (infinito positivo). En la práctica, el Mapobjeto no admite este valor, por lo que está sujeto a un nivel máximo más razonable permitido para una ubicación determinada.

Otra forma de decirlo: ¿cómo puede Mapsaber el objeto qué nivel de zoom debería elegir para una sola ubicación ? Quizás el valor óptimo debería ser 20 (si representa una dirección específica). O tal vez 11 (si representa una ciudad). O tal vez 6 (si representa un país). API no es tan inteligente y la decisión depende de usted.

Por lo tanto, simplemente debe verificar si markerssolo tiene una ubicación y, de ser así, usar uno de:

  • CameraUpdate cu = CameraUpdateFactory.newLatLng(marker.getPosition()) - ir a la posición del marcador, dejar intacto el nivel de zoom actual.
  • CameraUpdate cu = CameraUpdateFactory.newLatLngZoom(marker.getPosition(), 12F) - ir a la posición del marcador, establecer el nivel de zoom al valor 12 elegido arbitrariamente.
andr
fuente
21
Cabe señalar que el movimiento no puede ocurrir desde las llamadas onCreate, la vista debe ser creada. Necesitaba usar addOnGlobalLayoutListener para obtener la muestra adecuada.
Baruch Incluso el
66
@Bar Bueno, esto es en parte cierto. Para ser precisos: algunos métodos de movimiento no funcionarán justo después de crear el objeto de mapa. La razón de esto es que el objeto del mapa aún no se ha medido, es decir, no se ha sometido al proceso de diseño. Una solución típica es usar addOnGlobalLayoutListener()o post()con un apropiado Runnable. Esta es exactamente la razón por la cual no se pueden obtener las coordenadas de la pantalla del marcador onCreate; consulte stackoverflow.com/q/14429877/1820695. Sin embargo, puede usar algunos métodos incluso antes de que se haya realizado el diseño, por ejemplo. CameraUpdateFactory.newLatLngBounds()con 4 params .
andr
1
Hombre, me salvaste el día ... en realidad estaba tratando de hacerlo por mi cuenta, calculando los límites manualmente y haciendo zoom mientras el marcador está dentro ... estaba funcionando bastante feo, pero con tu método simple, funciona de maravilla. Gracias
Bibu
9
googleMap .setOnMapLoadedCallback (nuevo GoogleMap.OnMapLoadedCallback () {@Override public void onMapLoaded () {googleMap.moveCamera (cu);}}); Esto evitará el error en la medida.
Ramz
1
funciona de otra manera, pero cuando hay un solo marcador en el mapa, se acerca a un nivel extraño que el mapa se vuelve borroso. ¿Cómo arreglar esto?
Utsav Gupta
124

Google Map V2

La siguiente solución funciona para Android Marshmallow 6 (API 23, API 24, API 25, API 26, API 27, API 28). También funciona en 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
fuente
77
Para un acolchado más atractivo, use la altura en lugar del ancho y tome el 20% en lugar del 10%.
noob
2
La respuesta aceptada a veces causa un zoom extraño. Esto funciona como un encanto. Esta es una mejor respuesta.
Hüseyin Bülbül
1
Esta respuesta funciona mejor que la aceptada, la aceptada causa un comportamiento cansado.
Haytham
13

Entonces

Necesitaba usar addOnGlobalLayoutListener para obtener la muestra adecuada

por ejemplo, su mapa de Google está dentro de 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
fuente
1
Vine aquí del tutorial de Udemy, gran hombre de trabajo, usaron su respuesta para resolver el problema.
Shantanu Shady
13

No pude usar onGlobalLayoutlistener, así que aquí hay otra solución para evitar el "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."error:

mMap.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() { 
@Override 
public void onMapLoaded() { 
    mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(builder.build(), 15));
 } 
});
chrjs
fuente
Este toma mucho más tiempo que el OnGlobalLayoutListener, por lo que para mí todavía mostraba el área / zoom predeterminados de los mapas primero, antes de mover la cámara a mis necesidades
hasta el
Cómo dar algo de relleno ya que mis 2 marcadores se tocan con los límites del mapa.
Pratik Butani
9

Trabajando bien para mi.

A partir de este código, estoy mostrando múltiples marcadores con un zoom particular en la pantalla del mapa.

// Variables declaradas

private LatLngBounds bounds;
private LatLngBounds.Builder builder;

// Método para agregar múltiples puntos de marcador con icono dibujable

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

    }

// Para agregar múltiples marcadores visibles en el mapa

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

Nota : Esta no es una solución a la pregunta original. Esta es una solución a uno de los subproblemas discutidos anteriormente .

Solución a @andr Clarification 2 -

Es realmente problemático cuando solo hay un marcador en los límites y debido a ello, el nivel de zoom se establece en un nivel muy alto ( nivel 21 ). Y Google no proporciona ninguna forma de establecer el nivel máximo de zoom en este punto. Esto también puede suceder cuando hay más de 1 marcador, pero todos están bastante cerca uno del otro. Entonces también ocurrirá el mismo problema.

Solución : suponga que desea que su mapa nunca supere los 16 niveles de zoom. Luego, después de hacer ...

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

Comprueba si tu nivel de zoom ha cruzado el nivel 16 (o lo que quieras):

float currentZoom = mMap.getCameraPosition().zoom;

Y si este nivel es mayor que 16, lo que será solo si hay menos marcadores o si todos los marcadores están muy cerca el uno del otro, simplemente aleje el mapa en esa posición en particular solo ajustando el nivel de zoom a 16.

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

De esta manera, nunca tendrá el problema del nivel de zoom "extraño" explicado muy bien por @andr también.

Jyotman Singh
fuente
buena solución, pero si coloca el objeto "cu" dentro de MapReady (), entonces hay un mal comportamiento en este caso: la ubicación recibida -> el zoom es grande, así que haga 16 -> entonces el usuario se acerca -> la ubicación recibida nuevamente y la cámara se apaga volver al nivel 16 . Esto puede ser un problema cuando la ubicación se recibe casi en tiempo real, ya que seguirá volviendo al nivel 16.
Maher Nabil
"Y Google no proporciona ninguna forma de establecer el nivel máximo de zoom en este momento". - No es cierto: developers.google.com/android/reference/com/google/android/gms/…
user1209216
3

esto ayudaría ... de demos de 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));
                }
            });
        }
    }

para obtener información clara mira esta url. https://github.com/googlemaps/android-samples/blob/master/ApiDemos/app/src/main/java/com/example/mapdemo/MarkerDemoActivity.java

Amit Tumkur
fuente
1

Mostrar todos los marcadores con el mapa de Google

En estos métodos, almacene todos los marcadores y haga zoom automáticamente para mostrar todos los marcadores en el mapa de 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);
}
Sathish kumar TM
fuente
0

Use el método "getCenterCoordinate" para obtener la coordenada central y usar en 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
fuente
0

Tengo otra forma de hacer que esta misma cosa funcione perfectamente. Por lo tanto, la idea detrás de mostrar todos los marcadores en la pantalla es que necesitamos un centro lat largo y un nivel de zoom. Aquí está la función que le dará ambos y necesitará todos los objetos Latlng del marcador como entrada.

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

Esta función devuelve un objeto Pair que puede usar como

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

puede, en lugar de usar relleno para mantener sus marcadores alejados de los límites de la pantalla, puede ajustar el zoom en -1.

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