14

I am new to swift (iOS programming in general) and am trying to figure out how to zoom a map out to fit 2 points on the map.

Currently I have

var zoomRect = MKMapRectNull;
var myLocationPointRect = MKMapRectMake(myLocation.longitude, myLocation.latitude, 0, 0)
var currentDestinationPointRect = MKMapRectMake(currentDestination.longitude, currentDestination.latitude, 0, 0)

zoomRect = myLocationPointRect;
zoomRect = MKMapRectUnion(zoomRect, currentDestinationPointRect);

Which does nothing.

Do I have to apply zoomRect to the map somehow?

Wesley Skeen
  • 1,164
  • 3
  • 14
  • 22
  • By the way, please note `MKMapRectMake` accepts parameters of type `MKMapPoint` which are units that are _not_ the same as latitude and longitude degrees (`CLLocationDegrees`). Even though both are doubles, they are not in the same units. To convert from `CLLocationCoordinate2D` to `MKMapPoint`, use the `MKMapPointForCoordinate` function. But if you use the `showAnnotations` method, you don't need to do this conversion or create an `MKMapRect` manually. –  Nov 26 '14 at 20:25
  • See http://stackoverflow.com/questions/4680649/zooming-mkmapview-to-fit-annotation-pins for some Objective-C examples. –  Nov 26 '14 at 20:27

8 Answers8

36
self.mapView.showAnnotations(self.mapView.annotations, animated: true)
lveselovsky
  • 519
  • 5
  • 6
  • Best answer! The other ones are overly complicated that seemed to not work in certain situations. – Alan Dec 07 '17 at 20:54
  • I don't think that `showAnnotations` zooms to fit all annotations AND the current location. – GuanacoBE Aug 25 '19 at 14:31
6

MKMapRectUnion computes and returns a new rect, nothing more. You need to tell the mapView to set its visible area to that new rect:

myMapView.setVisibleMapRect(zoomRect, animated: true)
Eli Whittle
  • 1,084
  • 1
  • 15
  • 19
zisoft
  • 22,770
  • 10
  • 62
  • 73
  • @lveselovsky answer is not working for me in Swift 4, but thanks a lot, Above question, and this answer is worked perfectly for me. – Naveen Kumawat Dec 20 '18 at 10:55
6

Use below MKMapView extension-

extension MKMapView
{
    func fitAllMarkers(shouldIncludeCurrentLocation: Bool) {

        if !shouldIncludeCurrentLocation
        {
            showAnnotations(annotations, animated: true)
        }
        else
        {
            var zoomRect = MKMapRectNull

            let point = MKMapPointForCoordinate(userLocation.coordinate)
            let pointRect = MKMapRectMake(point.x, point.y, 0, 0)
            zoomRect = MKMapRectUnion(zoomRect, pointRect)

            for annotation in annotations {

                let annotationPoint = MKMapPointForCoordinate(annotation.coordinate)
                let pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0, 0)

                if (MKMapRectIsNull(zoomRect)) {
                    zoomRect = pointRect
                } else {
                    zoomRect = MKMapRectUnion(zoomRect, pointRect)
                }
            }

            setVisibleMapRect(zoomRect, edgePadding: UIEdgeInsetsMake(8, 8, 8, 8), animated: true)
        }
    }
}
Vishwas Singh
  • 1,497
  • 1
  • 18
  • 16
  • That else block seems overdone. Why not get the users current-location annotation through `self.mapView.userLocation` then add it to your annotations list, and then user `showAnnotations` ? – pnizzle Nov 08 '19 at 00:23
  • @pnizzle, won't an annotation for the current location get drawn as a pin and show up at the same location as the current location circle drawn by the map view? or is there a way to make an invisible annoation? – David Rector Jun 14 '22 at 18:52
3

For swift 3, iOS 10

Get current location first, and using call back didUpdateLocations to configure the map. Add the following code in your view controller:

@IBOutlet weak var mapView: MKMapView!

private var locationManager: CLLocationManager!

override func viewDidLoad() {
    super.viewDidLoad()

    mapView.delegate = self

    locationManager = CLLocationManager()
    locationManager.delegate = self
    locationManager.desiredAccuracy = kCLLocationAccuracyBest

    if CLLocationManager.locationServicesEnabled() {
        locationManager.requestWhenInUseAuthorization()
        locationManager.startUpdatingLocation()
    }
}



public func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    if let last = newLocation {
        let userlongitude = last.coordinate.longitude
        let userlatitude = last.coordinate.latitude
        let newDistance = CLLocation(latitude: userlatitude, longitude: userlongitude).distance(from: CLLocation(latitude: YourAnnotation.coordinate.latitude, longitude: YourAnnotation.coordinate.longitude))
        let region = MKCoordinateRegionMakeWithDistance(last.coordinate, 2 * newDistance, 2 * newDistance)
        let adjustRegion = self.mapView.regionThatFits(region)
        self.mapView.setRegion(adjustRegion, animated:true)
    }
}
Shan Ye
  • 2,622
  • 19
  • 21
1

-[MKMapView showAnnotations:animated:]

incanus
  • 5,100
  • 1
  • 13
  • 20
  • Do I put this after my code? is that objective c code? – Wesley Skeen Nov 26 '14 at 19:58
  • Yes, this is a method signature. Basically make an `NSArray` containing your points, pass it as the first argument, and pass a `BOOL` for the second argument. – incanus Dec 01 '14 at 19:37
0

As @lveselovsky said

self.mapView.showAnnotations(self.mapView.annotations, animated: true)

works perfectly.

If you are updating your UI before the map has loaded, you can put it in the delegate method like so:

func mapView(_ mapView: MKMapView, didUpdate userLocation: MKUserLocation) {
    guard !mapZoomUpdatedOnce else {
        return
    }

    self.mapView.showAnnotations(self.mapView.annotations, animated: true)
    self.mapZoomUpdatedOnce = true
}

Boolean value only to make sure once it's updated the first time, it does not get updated again if the user navigates somewhere else on the map :)

Mikkel Cortnum
  • 481
  • 4
  • 11
0

Swift 3 Fit all annotations in map. It's the correct way.

func zoomMapaFitAnnotations() {

        var zoomRect = MKMapRectNull
        for annotation in mapview.annotations {

            let annotationPoint = MKMapPointForCoordinate(annotation.coordinate)

            let pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0, 0)

            if (MKMapRectIsNull(zoomRect)) {
                zoomRect = pointRect
            } else {
                zoomRect = MKMapRectUnion(zoomRect, pointRect)
            }
        }
        self.mapview.setVisibleMapRect(zoomRect, edgePadding: UIEdgeInsetsMake(50, 50, 50, 50), animated: true)

    }
oscar castellon
  • 3,048
  • 30
  • 19
0

Add MKMapViewDelegate and connect mapView delegate in ViewDidLoad

mapView.delegate =. self


func mapView(_ mapView: MKMapView, didUpdate userLocation: MKUserLocation) {
    let region = MKCoordinateRegion(center: userLocation.coordinate, span: MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5))
    self.mapView.setRegion(region, animated: true)
}
amp.dev
  • 410
  • 4
  • 16