SwiftUI Map() delegate access.

Greetings,

I'm attempting to refactor a SwiftUI application.

From: IUViewRepresentable of MapView
To: SwiftUI's native Map() view.

However my application has to be able to react to the user's panning and zooming. In my UIViewRepresentable version, I added MKMapViewDelagate protocol to the Coordinator class, and create mapView(_ mapView:regionDidChangeAnimated)

How can assign a delegate class to the SwiftUI native version to accomplish this?

I've seen some posts use an init() method to adjust the appearance of the map with MKMapView.appearance(). Turns out this has a delegate property, but assigning a delegate here does not result in the mapView:regionDidChangeAnimated method being called...
Answered by BabyJ in 643077022
Map takes a Binding<MKCoordinateRegion> parameter so you can watch this for changes by adding the .onChange modifier.
Code Block Swift
struct MapView: View {
@State private var region = MKCoordinateRegion(...)
var body: some View {
Map(coordinateRegion: $region)
.onChange(of: region) { newRegion in
// the region changed to newRegion
}
}
}

Accepted Answer
Map takes a Binding<MKCoordinateRegion> parameter so you can watch this for changes by adding the .onChange modifier.
Code Block Swift
struct MapView: View {
@State private var region = MKCoordinateRegion(...)
var body: some View {
Map(coordinateRegion: $region)
.onChange(of: region) { newRegion in
// the region changed to newRegion
}
}
}

@BabyJ

Oh my goodness. I was afraid it was going to be something blindingly obvious. Thank you so much.
@BabyJ, Is there a modifier that fires just once when user let go of the map?
When I tried this, Xcode encountered an error that

Instance method 'onChange(of:perform:)' requires that 'MKCoordinateRegion' conform to 'Equatable'

I ended up adding a didSet:
Code Block swift
final class MapConfig: ObservableObject {
  var region: MKCoordinateRegion = MKCoordinateRegion(...)
  {
    didSet {
      print("changed to \(region)")
    }
  }
}
struct ChooseLocationView: View {
  @ObservedObject var config = MapConfig()
    
  var body: some View {
    ZStack {
      Map(coordinateRegion: $config.region,
      interactionModes: .all,
      showsUserLocation: true,
      userTrackingMode: nil)
    }
}
}



Listing to the Region will give you the following error:

Instance method 'onChange(of:perform:)' requires that 'MKCoordinateRegion' conform to 'Equatable'

To avoid this you could keep track of just one of the values of the region:

Code Block
.onChange(of: region.center.latitude){ newLatitude in ...
}

To solve this error:

Instance method 'onChange(of:perform:)' requires that 'MKCoordinateRegion' conform to 'Equatable'

you need to do conform 'MKCoordinateRegion' to 'Equatable' as it the error suggests. You can do it like eg. this:

import MapKit

extension MKCoordinateRegion: Equatable {
    public static func == (lhs: MKCoordinateRegion, rhs: MKCoordinateRegion) -> Bool {
        if lhs.center.latitude == rhs.center.latitude && lhs.span.latitudeDelta == rhs.span.latitudeDelta && lhs.span.longitudeDelta == rhs.span.longitudeDelta {
            return true
        } else {
            return false
        }
    }
}
SwiftUI Map() delegate access.
 
 
Q