SwiftUI and MapKit: Map camera position not updating when refreshing location

Map(initialPosition: .camera(mapCamera)) {
    Marker("Here", coordinate: location)
}
.frame(height: 300)
.clipShape(RoundedRectangle(cornerSize: CGSize(width: 10, height: 10)))
.onMapCameraChange(frequency: .continuous) { cameraContext in
    locationManager.location = cameraContext.camera.centerCoordinate
}
.onReceive(locationManager.$location, perform: { location in
    if let location {
        mapCamera.centerCoordinate = location
    }
})
class LocationDataManager: NSObject, CLLocationManagerDelegate, ObservableObject {
    
    enum LoadingState {
        case loading
        case notLoading
        case finished
    }
    
    static let shared = LocationDataManager()
    private let locationManager = CLLocationManager()
    @Published var location: CLLocationCoordinate2D? = nil
    @Published var loading: LoadingState = .notLoading
    
    override init() {
        super.init()
        
        locationManager.delegate = self
    }
    
    func resetLocation() {
        loading  = .notLoading
        location = nil
    }
    
    func getLocation() {
        locationManager.requestLocation()
        loading = .loading
    }
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        location = locations.first?.coordinate
        
        if location != nil {
            loading = .finished
        }
    }
    
    func locationManager(_ manager: CLLocationManager, didFailWithError error: any Error) {
        print("Failed to retrieve location: \(error.localizedDescription)")   
        loading = .notLoading
    }
}

So the when the LocationButton is selected, the location is found and the marker is set correctly. You can also move the camera around to adjust the marker position, which works correctly. However, if you press the LocationButton again, it updates the marker position but it won't move the MapCamera to the new location. I can see the marker move. mapCamera.centerCoordinate = location should be doing it, but it's not. Anyone know how to fix this?

Answered by Xavier-k in 788044022

I figured it out. You have to use mapCameraKeyframeAnimator().

    @State private var centerCoordinate = CLLocationCoordinate2D(latitude: 38.9072, longitude: -77.0369)
    @State private var distance: CLLocationDistance = 1000000
    @State private var triggerCamera = false
 Map(initialPosition: .camera(MapCamera(centerCoordinate: centerCoordinate, distance: distance))) {
                    
                }
                .frame(height: geo.size.height * 0.60)
                .shadow(color: .black.opacity(0.5), radius: 1, y: 1)
                .onReceive(locationManager.$location, perform: { location in
                    
                    if let location {
                        centerCoordinate = location
                        triggerCamera = true
                    }
                })
                .mapCameraKeyframeAnimator(trigger: triggerCamera, keyframes: { camera in
                    KeyframeTrack(\MapCamera.centerCoordinate, content: {
                        LinearKeyframe(centerCoordinate, duration: 1)
                    })
                    
                    KeyframeTrack(\MapCamera.distance, content: {
                        LinearKeyframe(300, duration: 1)
                    })
                })

Updating the trigger to true will start the animation, which moves to the provided location.

Accepted Answer

I figured it out. You have to use mapCameraKeyframeAnimator().

    @State private var centerCoordinate = CLLocationCoordinate2D(latitude: 38.9072, longitude: -77.0369)
    @State private var distance: CLLocationDistance = 1000000
    @State private var triggerCamera = false
 Map(initialPosition: .camera(MapCamera(centerCoordinate: centerCoordinate, distance: distance))) {
                    
                }
                .frame(height: geo.size.height * 0.60)
                .shadow(color: .black.opacity(0.5), radius: 1, y: 1)
                .onReceive(locationManager.$location, perform: { location in
                    
                    if let location {
                        centerCoordinate = location
                        triggerCamera = true
                    }
                })
                .mapCameraKeyframeAnimator(trigger: triggerCamera, keyframes: { camera in
                    KeyframeTrack(\MapCamera.centerCoordinate, content: {
                        LinearKeyframe(centerCoordinate, duration: 1)
                    })
                    
                    KeyframeTrack(\MapCamera.distance, content: {
                        LinearKeyframe(300, duration: 1)
                    })
                })

Updating the trigger to true will start the animation, which moves to the provided location.

SwiftUI and MapKit: Map camera position not updating when refreshing location
 
 
Q