Android map v2 zoom to show all the markers

167,347

Solution 1

You should use the CameraUpdate class to do (probably) all programmatic map movements.

To do this, first calculate the bounds of all the markers like so:

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

Then obtain a movement description object by using the factory: CameraUpdateFactory:

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

Finally move the map:

googleMap.moveCamera(cu);

Or if you want an animation:

googleMap.animateCamera(cu);

That's all :)

Clarification 1

Almost all movement methods require the Map object to have passed the layout process. You can wait for this to happen using the addOnGlobalLayoutListener construct. Details can be found in comments to this answer and remaining answers. You can also find a complete code for setting map extent using addOnGlobalLayoutListener here.

Clarification 2

One comment notes that using this method for only one marker results in map zoom set to a "bizarre" zoom level (which I believe to be maximum zoom level available for given location). I think this is expected because:

  1. The LatLngBounds bounds instance will have northeast property equal to southwest, meaning that the portion of area of the earth covered by this bounds is exactly zero. (This is logical since a single marker has no area.)
  2. By passing bounds to CameraUpdateFactory.newLatLngBounds you essentially request a calculation of such a zoom level that bounds (having zero area) will cover the whole map view.
  3. You can actually perform this calculation on a piece of paper. The theoretical zoom level that is the answer is +∞ (positive infinity). In practice the Map object doesn't support this value so it is clamped to a more reasonable maximum level allowed for given location.

Another way to put it: how can Map object know what zoom level should it choose for a single location? Maybe the optimal value should be 20 (if it represents a specific address). Or maybe 11 (if it represents a town). Or maybe 6 (if it represents a country). API isn't that smart and the decision is up to you.

So, you should simply check if markers has only one location and if so, use one of:

  • CameraUpdate cu = CameraUpdateFactory.newLatLng(marker.getPosition()) - go to marker position, leave current zoom level intact.
  • CameraUpdate cu = CameraUpdateFactory.newLatLngZoom(marker.getPosition(), 12F) - go to marker position, set zoom level to arbitrarily chosen value 12.

Solution 2

Google Map V2

The following solution works for Android Marshmallow 6 (API 23, API 24, API 25, API 26, API 27, API 28). It also works 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);

Solution 3

I couldnt use the onGlobalLayoutlistener, so here is another solution to prevent the "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));
 } 
});

Solution 4

So

I needed to use addOnGlobalLayoutListener to get the appropriate sample

for example, your Google Map is inside 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
        }
    });

Solution 5

Working fine for me.

From this code, I am displaying multiple markers with particular zoom on map screen.

// Declared variables

private LatLngBounds bounds;
private LatLngBounds.Builder builder;

// Method for adding multiple marker points with drawable icon

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

    }

// For adding multiple markers visible on map

@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);
Share:
167,347

Related videos on Youtube

Asanka Senavirathna
Author by

Asanka Senavirathna

Updated on September 16, 2020

Comments

  • Asanka Senavirathna
    Asanka Senavirathna over 3 years

    I have 10 markers in the GoogleMap. I want to zoom in as much as possible and keep all markers in view? In the earlier version this can be achieved from zoomToSpan() but in v2 I have no idea how about doing that. Further, I know the radius of the circle that needs to be visible.

  • Baruch Even
    Baruch Even almost 11 years
    It should be noted that the move cannot happen from the onCreate calls, the view must be created. I needed to use addOnGlobalLayoutListener to get the appropriate sample.
  • andr
    andr almost 11 years
    @Bar Well, this is partly true. To be precise: some movement methods won't work right after creating the map object. The reason for this is the map object hasn't been measured yet i.e. it has not undergone the layout process. A typical fix is to use addOnGlobalLayoutListener() or post() with an appropriate Runnable. This is exactly the reason why getting marker screen coordinates can't be done in onCreate - see stackoverflow.com/q/14429877/1820695 However you can use some methods even before layout has happened - eg. CameraUpdateFactory.newLatLngBounds() with 4 params.
  • Bibu
    Bibu about 10 years
    Man, you save my day ... was actually trying to do it on my own, calculate manually bounds, and zoom while marker is in it ... was working pretty ugly, but with your simple method, it works like a charm. Thanks
  • Ramz
    Ramz almost 10 years
    googleMap .setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() { @Override public void onMapLoaded() { googleMap.moveCamera(cu); } }); This will avoid the error on measure.
  • Utsav Gupta
    Utsav Gupta almost 10 years
    it works otherwise but when there is a single marker on map it zooms to some bizarre level that the map becomes to blurred. How to fix this?
  • Utsav Gupta
    Utsav Gupta almost 10 years
    isnt there a way to set a max limit to the zoom level in map irrespective of the the number of markers?
  • andr
    andr almost 10 years
    @user2103379 unfortunately no. see here for ugly workaround. although I once had an idea (which I never tested but you can): you save current map position to CameraPosition p1. then you proceed with calculating CameraUpdate cu like above and do map.moveCamera(cu). you save current position to p2 and check if its zoom is out of desired range - if so, you build new CameraPosition p3 based on p2 but with zoom corrected and issue map.moveCamera(p1); map.animateCamera(CameraUpdateFactory.newCameraPosition(p3))‌​; - warning: never tested.
  • Utsav Gupta
    Utsav Gupta almost 10 years
    Thanks, will test it if i get a chance.
  • jfmg
    jfmg over 8 years
    This code gave me the error: "the size of the map should not be 0". So what I had to do was to set the width and height of the map like this: final int width = getResources().getDisplayMetrics().widthPixels; final int height = getResources().getDisplayMetrics().heightPixels; final CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngBounds(latLngBounds, width, height, padding);.
  • android_dev
    android_dev over 8 years
    Thanks. If someone has a problem with app crash on googleMap.moveCamera(cu); checkout these answers stackoverflow.com/questions/13692579/…
  • Till
    Till almost 8 years
    This one takes way longer than the OnGlobalLayoutListener, so for me it still showed the maps default area/zoom first, before moving the camera to my needs
  • Maher Nabil
    Maher Nabil over 7 years
    good solution but if you put "cu" object inside onMapReady(), then there is a misbehavior in this case: location received -> zoom is large so make it 16 -> then the user zooms in -> location received again and camera is put back to level 16 . This can be a problem when location is received at almost real-time as it'll keep returning to level 16.
  • user1209216
    user1209216 almost 7 years
    " And Google does not provide any way to set the max zoom level at this point. " - Not true: developers.google.com/android/reference/com/google/android/g‌​ms/…
  • CrazyMind
    CrazyMind almost 7 years
    Thanks saved lots of time.
  • 0xC0DED00D
    0xC0DED00D almost 7 years
    For better-looking padding, use height instead of width and take 20% instead of 10% of it.
  • Baz
    Baz over 6 years
    Excellent answer, especially clarification 2!
  • Gowthaman M
    Gowthaman M over 6 years
    @andr **Error**com.google.maps.api.android.lib6.common.apiexceptio‌​n.c: Error using newLatLngBounds(LatLngBounds, int): 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. How can i solve can you help me please
  • andr
    andr over 6 years
    @GowthamanM this is already explained - see Clarification 1, Clarification 2 and my 2nd comment to the answer
  • Gowthaman M
    Gowthaman M over 6 years
    @andr ya sir..i got it.. i solved my pbm as well...Thank you so much
  • Shantanu Bedajna
    Shantanu Bedajna over 5 years
    Came here from the Udemy tutorial, great work man, they used your answer to solve the problem.
  • Hüseyin Bülbül
    Hüseyin Bülbül about 5 years
    Accepted answer sometimes cause weird zooming. This works like a charm. This is a better answer.
  • Pratik Butani
    Pratik Butani almost 5 years
    How to give some padding as my 2 markers are touched with map bounds.
  • Haytham
    Haytham almost 4 years
    This answer works better than the accepted one, the accepted one causes some weired behavior.
  • ankalagba
    ankalagba almost 3 years
    This does not work if the markers are very distant
  • Vatsal Dholakiya
    Vatsal Dholakiya over 2 years
    Thanks, It's working even in a loop.