Search code examples
swiftuimapkitcore-locationmkmapcamera

change SwiftUI Map position without resetting distance?


How would one update the position of a SwiftUI Map without impacting the zoom (or distance from a MapCamera point of view). So want overall want

  1. SwiftUI Map position being updated by incoming GPS co-ordinates from CLLocationManager
  2. A user can zoom in/out themselves on the map
  3. On subsequent GPS position changes I want to move the map to the new position only, and NOT change the zoom in/out (i.e. "distance" when using MapCamera) e

Issue: In my code below this is not working as when trying to get the "current distance" (aka Zoom) from MapCamera, which is "mapCamPost.camera?distance", this value seems to go to "nil" after the User zooms in the map. How can I fix this? Or another method with the new SwiftUI Map to solve this? (note I didn't have this issue with UIKit MKMapCamera)

struct GCMap: View {
    
    @StateObject var locationMgr = GcFlightState()
    @State private var mapCamPos: MapCameraPosition = .automatic
    
    var body: some View {
        ZStack {
            Map(position: $mapCamPos) {
                Annotation("UserLocation", coordinate: self.locationMgr.location.coordinate) {
                    Image(systemName: "airplane.circle").rotationEffect(.degrees(270))
                }
            }
            .onMapCameraChange() {
                print("onMapCameraChange \(mapCamPos.camera?.distance)")
            }
            .onReceive(locationMgr.$location) { location in
                mapCamPos =  .camera(MapCamera(
                    centerCoordinate: location.coordinate,
                    distance: mapCamPos.camera?.distance ?? 1000,   // <<===
                    heading: location.course
                ))
            }
            
        }
    }
}

Solution

  • You can track the camera's distance using an extra @State:

    @State private var distance = 1000.0
    
    .onMapCameraChange(frequency: .continuous) {
        distance = $0.camera.distance
    }
    

    Then you can use distance when creating the new MapCamera.