Zoom to fit current location and annotation on map
Asked Answered
B

8

16

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?

Bevy answered 26/11, 2014 at 19:44 Comment(2)
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.Starr
See #4681149 for some Objective-C examples.Starr
P
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)
Polio answered 26/11, 2014 at 20:20 Comment(1)
@Ogdoad answer is not working for me in Swift 4, but thanks a lot, Above question, and this answer is worked perfectly for me.Microdont
O
37
self.mapView.showAnnotations(self.mapView.annotations, animated: true)
Ogdoad answered 11/12, 2015 at 11:2 Comment(2)
Best answer! The other ones are overly complicated that seemed to not work in certain situations.Melo
I don't think that showAnnotations zooms to fit all annotations AND the current location.Metry
P
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)
Polio answered 26/11, 2014 at 20:20 Comment(1)
@Ogdoad answer is not working for me in Swift 4, but thanks a lot, Above question, and this answer is worked perfectly for me.Microdont
C
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)
        }
    }
}
Circulation answered 17/12, 2017 at 11:28 Comment(2)
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 ?Quaky
@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?Microscope
C
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)
    }
}
Coryza answered 7/9, 2017 at 15:40 Comment(0)
F
1

-[MKMapView showAnnotations:animated:]

Fina answered 26/11, 2014 at 19:57 Comment(2)
Do I put this after my code? is that objective c code?Bevy
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.Fina
M
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 :)

Martie answered 12/5, 2017 at 17:3 Comment(0)
G
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)

    }
Gavingavini answered 7/8, 2017 at 23:38 Comment(0)
I
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)
}
Ironbound answered 18/6, 2020 at 4:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.