Android map v2 zoom to show all the markers
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:
- The
LatLngBounds bounds
instance will havenortheast
property equal tosouthwest
, meaning that the portion of area of the earth covered by thisbounds
is exactly zero. (This is logical since a single marker has no area.) - By passing
bounds
toCameraUpdateFactory.newLatLngBounds
you essentially request a calculation of such a zoom level thatbounds
(having zero area) will cover the whole map view. - 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);
Related videos on Youtube
Asanka Senavirathna
Updated on September 16, 2020Comments
-
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 fromzoomToSpan()
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 almost 11 yearsIt 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 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()
orpost()
with an appropriateRunnable
. This is exactly the reason why getting marker screen coordinates can't be done inonCreate
- see stackoverflow.com/q/14429877/1820695 However you can use some methods even before layout has happened - eg.CameraUpdateFactory.newLatLngBounds()
with 4 params. -
Bibu about 10 yearsMan, 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 almost 10 yearsgoogleMap .setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() { @Override public void onMapLoaded() { googleMap.moveCamera(cu); } }); This will avoid the error on measure.
-
Utsav Gupta almost 10 yearsit 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 almost 10 yearsisnt there a way to set a max limit to the zoom level in map irrespective of the the number of markers?
-
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 calculatingCameraUpdate cu
like above and domap.moveCamera(cu)
. you save current position top2
and check if its zoom is out of desired range - if so, you build newCameraPosition p3
based onp2
but with zoom corrected and issuemap.moveCamera(p1); map.animateCamera(CameraUpdateFactory.newCameraPosition(p3));
- warning: never tested. -
Utsav Gupta almost 10 yearsThanks, will test it if i get a chance.
-
jfmg over 8 yearsThis 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 over 8 yearsThanks. If someone has a problem with app crash on googleMap.moveCamera(cu); checkout these answers stackoverflow.com/questions/13692579/…
-
Till almost 8 yearsThis 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 over 7 yearsgood 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 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/gms/…
-
CrazyMind almost 7 yearsThanks saved lots of time.
-
0xC0DED00D almost 7 yearsFor better-looking padding, use height instead of width and take 20% instead of 10% of it.
-
Baz over 6 yearsExcellent answer, especially clarification 2!
-
Gowthaman M over 6 years@andr **Error**
com.google.maps.api.android.lib6.common.apiexception.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 over 6 years@GowthamanM this is already explained - see Clarification 1, Clarification 2 and my 2nd comment to the answer
-
Gowthaman M over 6 years@andr ya sir..i got it.. i solved my pbm as well...Thank you so much
-
Shantanu Bedajna over 5 yearsCame here from the Udemy tutorial, great work man, they used your answer to solve the problem.
-
Hüseyin Bülbül about 5 yearsAccepted answer sometimes cause weird zooming. This works like a charm. This is a better answer.
-
Pratik Butani almost 5 yearsHow to give some padding as my 2 markers are touched with map bounds.
-
Haytham almost 4 yearsThis answer works better than the accepted one, the accepted one causes some weired behavior.
-
ankalagba almost 3 yearsThis does not work if the markers are very distant
-
Vatsal Dholakiya over 2 yearsThanks, It's working even in a loop.