swiftswiftuimapkitmkcoordinatespan

How to get current coordinate span in swiftUI?


I'm working with a map kit map and I need to get the current value of the coordinate span model. So that when you click on the map point, the map itself does not jump.

import SwiftUI
import MapKit

struct MapScreenView: View {

    @StateObject private var vm = LocationsViewModel()

    var body: some View {

        ZStack {
            VStack {
                HStack {
                    ButtonFilterView()
                    Spacer()
                }
                Spacer()
            }.zIndex(1)
            Map(coordinateRegion:
                    $vm.mapRegion, annotationItems: vm.locations) {
                location in
                MapAnnotation(coordinate: location.coordinate) {
                    LocationMapAnnotationView()
                        .scaleEffect(vm.mapLocation == location ? 1.1 : 0.7)
                        .animation(.easeInOut, value: vm.mapLocation == location)
                        .onTapGesture {
                            vm.showTappedLocation(location: location)
                        }
                }
            }
            .edgesIgnoringSafeArea(.all)
        }
    }
}

struct MapScreenView_Previews: PreviewProvider {
    static var previews: some View {
        MapScreenView()
    }
}




import Foundation
import MapKit
import SwiftUI

class LocationsViewModel: ObservableObject {

    @Published var locations: [Location] = LocationDataService.locations
    
    @Published var mapLocation: Location {
        didSet {
            updateMapRegion(location: mapLocation)
        }
    }

    @Published var mapRegion = MKCoordinateRegion()
    @Published var mapSpan = MKCoordinateSpan(latitudeDelta: 0.04, longitudeDelta: 0.04)
    
    init() {
        self.mapLocation = Location(name: "", coordinate: CLLocationCoordinate2D(latitude: 55.755864, longitude: 37.617698))
        updateMapRegion(location: Location(name: "", coordinate: CLLocationCoordinate2D(latitude: 55.755864, longitude: 37.617698)))
    }

    private func updateMapRegion(location: Location) {
        withAnimation(.easeInOut) {
            mapRegion = MKCoordinateRegion(
                center: location.coordinate,
                /// here i want get current span value
                span: location.name == "" ? MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1) : mapSpan
            )
        }
    }

    func showTappedLocation(location: Location) {
            mapLocation = location
    }
}

When I click on the map pin, it returns to the hard code span. How can I get current span? I searched for many solutions, but did not find the right one


Solution

  • SwiftUI Map takes a binding to a MKCoordinateRegion.

    In your code you have...

    Map(coordinateRegion: $vm.mapRegion, ...
    

    This is a twi way communication between the view model's region and the map view. When the map updates, this region updates. When you update the region, the map updates.

    So the current values of your map are help inside that mapRegion.

    Looking at the docs for MKCoordinateRegion https://developer.apple.com/documentation/mapkit/mkcoordinateregion/1452293-span

    It has a property span which is an MKCoordinateSpan.

    So in the view model... this is the current span of the map.

    To update your function you could do something like...

    private func updateMapRegion(location: Location) {
        withAnimation(.easeInOut) {
            mapRegion = MKCoordinateRegion(
                center: location.coordinate,
                /// here i want get current span value
                span: mapRegion.span
            )
        }
    }
    

    Having said that, you seem to be creating a whole new region here. I don't know if that's a good idea. You could just update the center of the existing region without creating a whole new one.

    private func updateMapRegion(location: Location) {
        withAnimation(.easeInOut) {
            mapRegion.center = location.coordinate
        }
    }