Android map v2 zoom pour afficher tous les marqueurs

286

J'ai 10 marqueurs dans le GoogleMap. Je souhaite zoomer autant que possible et garder tous les marqueurs en vue? Dans la version précédente, cela peut être réalisé à partir de zoomToSpan()mais dans la v2, je ne sais pas comment faire cela. De plus, je connais le rayon du cercle qui doit être visible.

Asanka Senavirathna
la source

Réponses:

810

Vous devez utiliser la CameraUpdateclasse pour effectuer (probablement) tous les mouvements de carte programmatiques.

Pour ce faire, calculez d'abord les limites de tous les marqueurs comme ceci:

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

Obtenez ensuite un objet de description de mouvement en utilisant l'usine CameraUpdateFactory::

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

Déplacez enfin la carte:

googleMap.moveCamera(cu);

Ou si vous voulez une animation:

googleMap.animateCamera(cu);

C'est tout :)

Clarification 1

Presque toutes les méthodes de mouvement nécessitent que l' Mapobjet ait réussi le processus de mise en page. Vous pouvez attendre que cela se produise en utilisant la addOnGlobalLayoutListenerconstruction. Des détails peuvent être trouvés dans les commentaires de cette réponse et des réponses restantes. Vous pouvez également trouver un code complet pour définir l'étendue de la carte en utilisant addOnGlobalLayoutListenerici .

Clarification 2

Un commentaire note que l'utilisation de cette méthode pour un seul marqueur entraîne un zoom de la carte réglé sur un niveau de zoom "bizarre" (qui je pense être le niveau de zoom maximum disponible pour un emplacement donné). Je pense que cela est attendu parce que:

  1. L' LatLngBounds boundsinstance aura une northeastpropriété égale à southwest, ce qui signifie que la partie de la surface de la terre couverte par celle-ci boundsest exactement nulle. (Cela est logique car un seul marqueur n'a pas de zone.)
  2. En passant boundsà CameraUpdateFactory.newLatLngBoundsvous, demandez essentiellement un calcul d'un tel niveau de zoom qui bounds(ayant une zone nulle) couvrira toute la vue de la carte.
  3. Vous pouvez réellement effectuer ce calcul sur une feuille de papier. Le niveau de zoom théorique qui est la réponse est + ∞ (infini positif). En pratique, l' Mapobjet ne prend pas en charge cette valeur, il est donc fixé à un niveau maximum plus raisonnable autorisé pour un emplacement donné.

Une autre façon de le dire: comment l' Mapobjet peut-il savoir quel niveau de zoom doit-il choisir pour un seul emplacement ? Peut-être que la valeur optimale devrait être 20 (si elle représente une adresse spécifique). Ou peut-être 11 (si cela représente une ville). Ou peut-être 6 (s'il représente un pays). L'API n'est pas si intelligente et la décision vous appartient.

Donc, vous devez simplement vérifier si markersn'a qu'un seul emplacement et si oui, utilisez l'un des:

  • CameraUpdate cu = CameraUpdateFactory.newLatLng(marker.getPosition()) - allez à la position du marqueur, laissez le niveau de zoom actuel intact.
  • CameraUpdate cu = CameraUpdateFactory.newLatLngZoom(marker.getPosition(), 12F) - aller à la position du marqueur, régler le niveau de zoom sur la valeur choisie arbitrairement 12.
andr
la source
21
Il convient de noter que le déplacement ne peut pas se produire à partir des appels onCreate, la vue doit être créée. J'avais besoin d'utiliser addOnGlobalLayoutListener pour obtenir l'échantillon approprié.
Baruch Even
6
@Bar Eh bien, c'est en partie vrai. Pour être précis: certaines méthodes de déplacement ne fonctionneront pas juste après la création de l'objet de la carte. La raison en est que l'objet cartographique n'a pas encore été mesuré , c'est-à-dire qu'il n'a pas subi le processus de mise en page. Une solution typique consiste à utiliser addOnGlobalLayoutListener()ou post()avec une solution appropriée Runnable. C'est exactement la raison pour laquelle obtenir les coordonnées de l'écran du marqueur ne peut pas être fait dans onCreate- voir stackoverflow.com/q/14429877/1820695 Cependant, vous pouvez utiliser certaines méthodes avant même que la mise en page se soit produite - par exemple. CameraUpdateFactory.newLatLngBounds()avec 4 paramètres .
andr
1
Mec, tu sauves ma journée ... essayais en fait de le faire par moi-même, calculais manuellement les limites et zoomais pendant que le marqueur était dedans ... fonctionnait assez moche, mais avec ta méthode simple, ça marche comme un charme. Merci
Bibu
9
googleMap .setOnMapLoadedCallback (nouveau GoogleMap.OnMapLoadedCallback () {@Override public void onMapLoaded () {googleMap.moveCamera (cu);}}); Cela évitera l'erreur de mesure.
Ramz
1
cela fonctionne autrement, mais lorsqu'il n'y a qu'un seul marqueur sur la carte, il zoome à un niveau bizarre que la carte devient floue. Comment régler ceci?
Utsav Gupta
124

Google Map V2

La solution suivante fonctionne pour Android Marshmallow 6 (API 23, API 24, API 25, API 26, API 27, API 28). Il fonctionne également dans 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
la source
7
Pour un rembourrage plus beau, utilisez la hauteur au lieu de la largeur et prenez 20% au lieu de 10%.
Noob
2
La réponse acceptée provoque parfois un zoom étrange. Cela fonctionne comme un charme. C'est une meilleure réponse.
Hüseyin Bülbül
1
Cette réponse fonctionne mieux que celle acceptée, la réponse acceptée provoque un certain comportement bizarre.
Haytham
13

Alors

J'avais besoin d'utiliser addOnGlobalLayoutListener pour obtenir l'échantillon approprié

par exemple, votre carte Google se trouve dans 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
la source
1
Issu du tutoriel Udemy, grand homme de travail, ils ont utilisé votre réponse pour résoudre le problème.
Shantanu Shady du
13

Je ne pouvais pas utiliser le onGlobalLayoutlistener, voici donc une autre solution pour éviter 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."erreur:

mMap.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() { 
@Override 
public void onMapLoaded() { 
    mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(builder.build(), 15));
 } 
});
chrjs
la source
Celui - ci prend beaucoup plus longue que la OnGlobalLayoutListener, donc pour moi , il a montré encore les cartes zone par défaut / zoom d' abord, avant de déplacer l'appareil photo à mes besoins
Jusqu'à
Comment donner du rembourrage car mes 2 marqueurs sont touchés par les limites de la carte.
Pratik Butani,
9

Ça marche bien pour moi.

À partir de ce code, j'affiche plusieurs marqueurs avec un zoom particulier sur l'écran de la carte.

// Variables déclarées

private LatLngBounds bounds;
private LatLngBounds.Builder builder;

// Méthode pour ajouter plusieurs points de marqueur avec une icône dessinable

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

    }

// Pour ajouter plusieurs marqueurs visibles sur la carte

@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
la source
4

Remarque - Ce n'est pas une solution à la question d'origine. Ceci est une solution à l'un des sous-problèmes discutés ci - dessus .

Solution à @andr Clarification 2 -

C'est vraiment problématique quand il n'y a qu'un seul marqueur dans les limites et à cause de cela le niveau de zoom est réglé à un niveau très élevé ( niveau 21 ). Et Google ne fournit aucun moyen de définir le niveau de zoom maximal à ce stade. Cela peut également se produire lorsqu'il y a plus d'un marqueur mais qu'ils sont tous assez proches les uns des autres. Ensuite, le même problème se produira également.

Solution - Supposons que vous souhaitiez que votre carte ne dépasse jamais le niveau de zoom 16. Puis après avoir fait -

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

Vérifiez si votre niveau de zoom a franchi le niveau 16 (ou ce que vous voulez) -

float currentZoom = mMap.getCameraPosition().zoom;

Et si ce niveau est supérieur à 16, ce qui ne sera le cas que s'il y a très moins de marqueurs ou si tous les marqueurs sont très proches les uns des autres, il vous suffit de faire un zoom arrière sur votre carte à cette position particulière uniquement en réglant le niveau de zoom sur 16.

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

De cette façon, vous n'aurez jamais le problème du niveau de zoom "bizarre" très bien expliqué par @andr.

Jyotman Singh
la source
bonne solution mais si vous placez un objet "cu" à l'intérieur de onMapReady (), alors il y a un mauvais comportement dans ce cas: l' emplacement reçu -> le zoom est grand alors faites-le 16 -> puis l'utilisateur fait un zoom avant -> l'emplacement reçu à nouveau et l'appareil photo est remis au niveau 16 . Cela peut être un problème lorsque la localisation est reçue presque en temps réel car elle continuera de revenir au niveau 16.
Maher Nabil
"Et Google ne fournit aucun moyen de définir le niveau de zoom maximal à ce stade."
Faux
3

cela aiderait .. à partir de démos 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));
                }
            });
        }
    }

pour des informations claires, regardez cette URL. https://github.com/googlemaps/android-samples/blob/master/ApiDemos/app/src/main/java/com/example/mapdemo/MarkerDemoActivity.java

Amit Tumkur
la source
1

J'ai eu un problème similaire, l'utilisation du code suivant a résolu le problème:

CameraUpdateFactory.newLatLngBounds(bounds, 200, 200, 5) généralement, les différences de localisation dans mon cas ne sont pas plus de deux villes voisines.

zoom pour s'adapter à tous les marqueurs sur la carte google maps v2

Avishkar Ramjeet
la source
1

Afficher tous les marqueurs avec Google map

Dans ces méthodes, stockez tous les marqueurs et zoomez automatiquement pour afficher tous les marqueurs dans 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
la source
0

Utilisez la méthode "getCenterCoordinate" pour obtenir les coordonnées centrales et les utiliser dans 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
la source
0

J'ai une autre façon de faire cette même chose fonctionne parfaitement. donc l'idée derrière pour afficher tous les marqueurs sur l'écran, nous avons besoin d'un centre de lat long et d'un niveau de zoom. voici la fonction qui vous donnera les deux et aura besoin de tous les objets Latlng du marqueur en entrée.

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

Cette fonction renvoie un objet Pair que vous pouvez utiliser comme

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

vous pouvez au lieu d'utiliser un rembourrage pour éloigner vos marqueurs des limites de l'écran, vous pouvez régler le zoom de -1.

Anuj Jindal
la source
-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
la source