54

I want to show all the markers that are on my map, after doing some searches I found that it should be done with GMSCoordinateBounds (Google Maps SDK) I've read the official documentation about it, but I have not understand how to use it and implement it in my code.

https://developers.google.com/maps/documentation/ios/reference/interface_g_m_s_camera_update#aa5b05606808272f9054c54af6830df3e

Here is my code

GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc] init];   
CLLocationCoordinate2D location;

for (NSDictionary *dictionary in array) {
    location.latitude = [dictionary[@"latitude"] floatValue];
    location.longitude = [dictionary[@"longitude"] floatValue];

    // Creates a marker in the center of the map.
    GMSMarker *marker = [[GMSMarker alloc] init];
    marker.icon = [UIImage imageNamed:(@"marker.png")];
    marker.position = CLLocationCoordinate2DMake(location.latitude, location.longitude);
    bounds = [bounds includingCoordinate:marker.position];
    marker.title = dictionary[@"type"];
    marker.map = mapView_;
}   

[mapView_ animateWithCameraUpdate:[GMSCameraUpdate fitBounds:bounds withPadding:30.0f]];

Any help ?

shim
  • 9,289
  • 12
  • 69
  • 108
Al_fareS
  • 725
  • 1
  • 9
  • 18

10 Answers10

61
- (void)focusMapToShowAllMarkers
{

    GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc] init];

    for (GMSMarker *marker in <An array of your markers>)
        bounds = [bounds includingCoordinate:marker.position];

    [<yourMap> animateWithCameraUpdate:[GMSCameraUpdate fitBounds:bounds withPadding:30.0f]];


}

UPDATE:

are you sure there is nothing wrong in you array of markers and the coordinates? I've tried this code and is working perfectly. I've put this on the viewDidAppear

NSMutableArray *array = [[NSMutableArray alloc]initWithObjects:[[NSDictionary alloc]initWithObjectsAndKeys:@"44.66",@"latitude",@"21.33",@"longitude", nil],
                         [[NSDictionary alloc]initWithObjectsAndKeys:@"44.66",@"latitude",@"21.453",@"longitude", nil],
                         [[NSDictionary alloc]initWithObjectsAndKeys:@"44.44",@"latitude",@"21.993",@"longitude", nil],
                         [[NSDictionary alloc]initWithObjectsAndKeys:@"44.635",@"latitude",@"21.553",@"longitude", nil],
                         [[NSDictionary alloc]initWithObjectsAndKeys:@"44.3546",@"latitude",@"21.663",@"longitude", nil],
                         [[NSDictionary alloc]initWithObjectsAndKeys:@"44.6643",@"latitude",@"21.212",@"longitude", nil],
                         [[NSDictionary alloc]initWithObjectsAndKeys:@"44.63466",@"latitude",@"21.3523",@"longitude", nil],nil];
GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc] init];
CLLocationCoordinate2D location;
for (NSDictionary *dictionary in array)
{
    location.latitude = [dictionary[@"latitude"] floatValue];
    location.longitude = [dictionary[@"longitude"] floatValue];
    // Creates a marker in the center of the map.
    GMSMarker *marker = [[GMSMarker alloc] init];
    marker.icon = [UIImage imageNamed:(@"marker.png")];
    marker.position = CLLocationCoordinate2DMake(location.latitude, location.longitude);
    bounds = [bounds includingCoordinate:marker.position];
    marker.title = dictionary[@"type"];
    marker.map = mapView_;
}
[mapView_ animateWithCameraUpdate:[GMSCameraUpdate fitBounds:bounds withPadding:30.0f]];

This is my result:

map with markers

allemattio
  • 1,836
  • 17
  • 33
  • It apears with a very big zoom out ! it show the map of the world :s – Al_fareS Feb 07 '14 at 10:21
  • I think you're doing something wrong, works perfectly in my app, please post your code.. – allemattio Feb 07 '14 at 10:39
  • I've just updated my post, and included the code I use, please check it. – Al_fareS Feb 07 '14 at 10:57
  • Well, I've just used your code, and what I see is marker behind marker as the previous problem I had, it is zoomed out, can you please show me a screenshot of what you have ? Because what I request is to Zoom-in to-Fit All Markers. – Al_fareS Feb 07 '14 at 12:21
  • Well, what I see when runing is zoomed out much more than this, is it possible for you to upload this part of project on github as demo, so I can run and have the same result, because I take your code and I do the same runing on my iphone, and I obtain it zoomed out much more than this. – Al_fareS Feb 07 '14 at 17:25
  • 3
    @Al_fareS I tried allemattio code in viewDidLoad and the result appeared with a very big zoom out. It showed the map of the world. But then, I moved the code to viewDidAppear as actually suggested by allemattio, and the results appeared fine, just like the allemattio's screenshot. – Indrajeet Mar 31 '14 at 16:38
  • 1
    Right, moving this code to viewWillAppear solved the problem of "world size scale" – alex Apr 28 '15 at 13:48
  • It still doesn't work for me. I use the exact same code, it's in the viewDidAppear too. But, it shows world map. what version of Google Maps SDK are you using? @allemattio – Peyman Jun 22 '15 at 21:16
  • swift version `var bounds = GMSCoordinateBounds() //loop bounds.includingCoordinate(marker.position) //end loop self.mapView.camera = self.mapView.cameraForBounds(bounds, insets: UIEdgeInsetsZero)` – iluvatar_GR Nov 17 '15 at 19:47
  • I have tried with but not working as I am using tabbar and navigationbar – Himanth May 15 '17 at 08:17
  • @allemattio's answer is correct upto 90%, the only issue of large zoom out that Al_fareS is facing is that we need to give a delay before we can call animateWIthCameraUpdate . The detailed answer is in the following link: https://stackoverflow.com/questions/30928442/fit-entire-google-map-in-zoom-level-in-swift-project – GKK Jul 27 '17 at 09:29
  • Very Nice Solutions – Bhumesh Purohit Feb 05 '18 at 07:05
43

Swift 3 - Xcode 8

var bounds = GMSCoordinateBounds()
        for marker in yourArrayOfMarkers
        {
            bounds = bounds.includingCoordinate(marker.position)
        }
        let update = GMSCameraUpdate.fit(bounds, withPadding: 60)
        mapView.animate(with: update)
Channel
  • 2,183
  • 21
  • 16
  • 1
    if all pins don't display on the mapView, check you have not limited the mapView min and max zoom – Hashem Aboonajmi Sep 03 '17 at 06:33
  • 1
    Also if you find the map zoomed out to maximum, make sure mapView.frame is set correctly. – Ali Amin Jun 09 '18 at 07:27
  • Thanks for the `mapView.frame` tip @AliAmin - I had a frame of `.zero` as recommended in the docs and it wasn't zooming! – Inti Jul 15 '19 at 17:11
  • Right, and your have to make sure your map view is already layout. Better call this in viewDidLayoutSubviews callback. – StoneLam Dec 12 '19 at 09:42
21

Clean swift 3 version:

let bounds = markers.reduce(GMSCoordinateBounds()) { 
    $0.includingCoordinate($1.position) 
}

mapView.animate(with: .fit(bounds, withPadding: 30.0))
average Joe
  • 4,377
  • 2
  • 25
  • 23
17

Swift solution using GMSCoordinateBounds() without path,

var bounds = GMSCoordinateBounds()
for location in locationArray
{
    let latitude = location.valueForKey("latitude")
    let longitude = location.valueForKey("longitude")

    let marker = GMSMarker()
    marker.position = CLLocationCoordinate2D(latitude:latitude, longitude:longitude)
    marker.map = self.mapView
    bounds = bounds.includingCoordinate(marker.position)
}
let update = GMSCameraUpdate.fitBounds(bounds, withPadding: 100)
mapView.animateWithCameraUpdate(update)
Arpit Dongre
  • 1,683
  • 19
  • 30
9

The easiest way I have found is to create a GMSMutablePath and then add all the coordinates of your markers to it. Then you can use the GMSCoordinateBounds initializer initWithPath: to create the bounds.

Once you have the bounds, you can create the GMSCameraUpdate and use it to animate the map to the visible bounds containing all of your markers.

For example, if you have an array of GMSMarker's:

NSArray *myMarkers;   // array of marker which sets in Mapview
GMSMutablePath *path = [GMSMutablePath path];

for (GMSMarker *marker in myMarkers) { 
   [path addCoordinate: marker.position];
}
GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc] initWithPath:path];

[_mapView animateWithCameraUpdate:[GMSCameraUpdate fitBounds:bounds]];
Sommm
  • 527
  • 4
  • 22
mars
  • 1,651
  • 2
  • 15
  • 20
8

As for Google Maps version 2.0.0 if you try to create a GMSCoordinateBounds using the default constructor GMSCoordinateBounds() and you check the "valid" flag it will be returning false and it won't make the animateWithCameraUpdate: move.

Swift 2.3 Solution

    if let myLocation = mapView.myLocation {
        let path = GMSMutablePath()
        path.addCoordinate(myLocation.coordinate)

        //add other coordinates 
        //path.addCoordinate(model.coordinate)

        let bounds = GMSCoordinateBounds(path: path)
        mapView.animateWithCameraUpdate(GMSCameraUpdate.fitBounds(bounds, withPadding: 40))
    }
apinho
  • 2,235
  • 3
  • 25
  • 39
7
@IBOutlet weak var mapView: GMSMapView!

let camera = GMSCameraPosition.cameraWithLatitude(23.0793, longitude:  
72.4957, zoom: 5)
mapView.camera = camera
mapView.delegate = self
mapView.myLocationEnabled = true

*** arry has dictionary object which has value of Latitude and Longitude. ***
let path = GMSMutablePath()

for i in 0..<arry.count {

   let dict = arry[i] as! [String:AnyObject]
   let latTemp =  dict["latitude"] as! Double
   let longTemp =  dict["longitude"] as! Double

   let marker = GMSMarker()
   marker.position = CLLocationCoordinate2D(latitude: latTemp, longitude: longTemp)
   marker.title = "Austrilia"
   marker.appearAnimation = kGMSMarkerAnimationNone
   marker.map = self.mapView

   path.addCoordinate(CLLocationCoordinate2DMake(latTemp, longTemp))

  } 

  let bounds = GMSCoordinateBounds(path: path)
  self.mapView!.animateWithCameraUpdate(GMSCameraUpdate.fitBounds(bounds, withPadding: 50.0))
Dipang
  • 1,111
  • 12
  • 12
4

We can find the same code every where , but make sure that it is in viewDidAppear() method

//bounding to a region of markers
GMSCoordinateBounds *bounds =
[[GMSCoordinateBounds alloc] initWithCoordinate:sourceMarker.position coordinate:destMarker.position];
[_mapView moveCamera:[GMSCameraUpdate fitBounds:bounds withPadding:50.0]];
Zeesha
  • 991
  • 9
  • 14
1

You could iterate your map markers and get the further point to the east, west, north and south and make [[GMSCoordinateBounds alloc] initWithRegion:]

Davi Stuart
  • 269
  • 3
  • 16
  • 1
    Thanks for your answer, can you please be more specific as I am a newbie, a code snippet will be very helpful to clearly understand the idea. – Al_fareS Feb 07 '14 at 01:02
1

As per documentation, GMSCoordinateBounds can't be mutated.

GMSCoordinateBounds is immutable and can't be modified after construction.

- (GMSCoordinateBounds *)includingCoordinate:(CLLocationCoordinate2D)coordinate;
- (GMSCoordinateBounds *)includingBounds:(GMSCoordinateBounds *)other;

So we can mutate GMSCoordinateBounds by using above methods includingCoordinate: (for extending coordinates) and includingBounds: (for extending bounds).

So Swift code will looks like below:

var gmsBounds = GMSCoordinateBounds()
for coordinate in coordinates {
    let marker = GMSMarker(position: coordinate)
    gmsBounds = gmsBounds.includingCoordinate(position)
    marker.map = mapView
}
mapView.animate(with: GMSCameraUpdate.fit(gmsBounds, withPadding: 30.0))

Additional Notes:

If you add custom marker view, add padding as width of marker view in addition to required padding.