Tom Clifford
Tom Clifford

Reputation: 85

iOS MapKit followWithHeading not making map rotate

I'm planning on building an app that uses MapKit and core location. To get started with this I'm simply trying to create a basic map view that will show the users location and rotate the map to match the direction the devices is facing, much like the standard Maps app does when you tap the current location button twice.

I've followed some basic guides to use a UIViewRepresentable to display an MKMapView in a Swift UI app and have so far produced this code:

BasicMapViewUI.Swift:

import SwiftUI
import MapKit

struct BasicMapViewUI: UIViewRepresentable
{
    func makeUIView(context: Context) -> MKMapView
    {
        let myMapView = MKMapView()
        myMapView.showsUserLocation = true
        myMapView.userTrackingMode = .followWithHeading
        myMapView.showsCompass = true
        return myMapView
    }
    
    func updateUIView(_ uiView: MKMapView, context: Context)
    {
        print("updateUIView Called")
    }
    
    typealias UIViewType = MKMapView
}

BasicLocationManager.Swift

import Foundation
import CoreLocation

class BasicLocationManager: NSObject, ObservableObject
{
    var locationManager = CLLocationManager()
    
    func startLocationServices()
    {
        locationManager.startUpdatingLocation()
        locationManager.startUpdatingHeading()
    }
    
    override init()
    {
        super.init()
        locationManager.delegate = self
    }
}

extension BasicLocationManager: CLLocationManagerDelegate
{
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
    {
        guard let latest = locations.first else { return }
        let heading = latest.course
        print(latest)
    }
    
    func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading)
    {
        let latest = newHeading
        print(latest)
    }
}

BasicMapView.Swift:

import SwiftUI

struct BasicMapView: View
{
    @StateObject var myLocationManager = BasicLocationManager()
    var body: some View
    {
        ZStack
        {
            BasicMapViewUI()
                .edgesIgnoringSafeArea(.all)
        }.onAppear {
            print("onAppear")
            myLocationManager.startLocationServices()
        }
    }
}

(I know I shouldn't have startLocationServices called here but it seemed like the simplest way for this sandbox type example)

My main app file just calls BasicMapView()

When I run the app on my device, the map displays and the dot is in the correct location, but the map does not rotate with the direction of the device.

The documentation implies that the line myMapView.userTrackingMode = .followWithHeading should make the map rotate automatically when the heading changes.

I can tell from the didUpdateHeading function in the location manager delegate that the heading is correctly updating.

I'd be very grateful if anyone could help me understand this.

Upvotes: 2

Views: 864

Answers (1)

Jason Crocker
Jason Crocker

Reputation: 541

I used storyboards rather than SwiftUI, but my solution was to have my MapViewController (a basic UIViewController containing an MKMapView) be the MKMapViewDelegate delegate of the MKMapView, and in the mapView(_ mapView: MKMapView, didUpdate userLocation: MKUserLocation) delegate method, set mapView.userTrackingMode = .followWithHeading the first time the method was called.

Upvotes: 0

Related Questions