Usman
Usman

Reputation: 618

setUserTrackingMode to MKUserTrackingModeFollow without changing zoom level

At Apple Documentation of setUserTrackingMode:animated:

it is stated that:

Setting the tracking mode to MKUserTrackingModeFollow or MKUserTrackingModeFollowWithHeading causes the map view to center the map on that location and begin tracking the user’s location. If the map is zoomed out, the map view automatically zooms in on the user’s location, effectively changing the current visible region.

My question, is there a way we can retain current zoom level on map, while setting the user tracking mode?

Upvotes: 4

Views: 2853

Answers (4)

piotros
piotros

Reputation: 41

There is a way to do it in a smooth way by getting the location of the default MKUserLocation bubble. Just a note, MKUserLocation.location will not return smoothed out location as it's updated when location manager updates, but we can get the location of the actual bubble annotation view. We can then use CADisplayLink to update the map every frame:

// in viewDidLoad
displayLink = CADisplayLink(target: self, selector: #selector(displayStep))
displayLink?.add(to: .current, forMode: .default)


@objc
func displayStep(displayLink: CADisplayLink) {

    if let annotation = mapView.annotations.filterByType(MKUserLocation.self).first,
       let annotationView = mapView.view(for: annotation) {

        let smoothedLocation = mapView.convert(annotationView.frame, toRegionFrom: nil).center

        //set the camera to the smoothed location 
        mapView.camera.centerCoordinate = smoothedLocation
   }
}

Upvotes: 1

MightyMeta
MightyMeta

Reputation: 609

As of iOS 13 you can set a minimum map zoom level, which prevents MKUserTrackingModeFollow getting any closer than the specified distance, when it is set:

let minZoom: CLLocationDistance = 10000 // desired visible radius from user in metres    
let zoomRange = MKMapView.CameraZoomRange(minCenterCoordinateDistance: minZoom)
mapView.setCameraZoomRange(zoomRange, animated: true)

https://developer.apple.com/documentation/mapkit/mkmapview/camerazoomrange

Upvotes: 2

Stephen Weiler
Stephen Weiler

Reputation: 11

The way i was able to do this was to call a MKCoordinateRegionMakeWithDistance call that uses the users location and center. I used 5000 for my values. This is what my test code looks like. `import UIKit import CoreLocation import MapKit

class ViewController: UIViewController, CLLocationManagerDelegate{

@IBOutlet weak var mapView: MKMapView!

var locationManager = CLLocationManager()

override func viewDidLoad() {
    super.viewDidLoad()

    if (CLLocationManager.locationServicesEnabled()){
        mapView.showsUserLocation = true
        mapView.mapType = MKMapType.satellite
        mapView.setUserTrackingMode(MKUserTrackingMode.followWithHeading, animated: true)
        //locationManager = CLLocationManager()
        //locationManager.delegate = self
        //locationManager.desiredAccuracy = kCLLocationAccuracyBest
        //locationManager.requestAlwaysAuthorization()
        //locationManager.startUpdatingLocation()
    }


}


/*func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
    let location = locations.last as! CLLocation

    let center = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
    //let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
    let region = MKCoordinateRegionMakeWithDistance(center, 500, 500)

    self.mapView.setRegion(region, animated: true)
}*/


@IBAction func centerButton(_ sender: UIButton, forEvent event: UIEvent) {
    let location = MKUserLocation()
    let center = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
    let region = MKCoordinateRegionMakeWithDistance(center, 5000, 5000)
    self.mapView.setRegion(region, animated: true)
    mapView.setUserTrackingMode(MKUserTrackingMode.followWithHeading, animated: true)

}

} ` dont read any of the commented out locationManager info. The important thing here is to remember that calling setUserTrackingMode does not affect the zoom level but just moves the center to the users location so if you set a zoom level using the region and distance method, and then call setUserTrackingMode it will assume that zoom. This allows me to always zoom out to a reasonable zoom level each time we recenter and follow the users current location.

Upvotes: 1

incanus
incanus

Reputation: 5128

No. One alternative is you could listen to user location updates yourself (either through Core Location or the MKMapViewDelegate methods and update the map center, but tracking mode can not guarantee to not change the zoom.

Upvotes: 0

Related Questions