Building a mostly SwiftUI app... I'm trying to connect (bind) the value of a BindableObject in a parent view to a MapKit child view, such that when the annotation (callout accessory) is tapped (the little (i) button on the annotation label...
...it changes the value of $showDetails to true, which is wired up to a "sheet(isPresented: $showDetails...)" further up the view hierarchy, which then displays a modal:
struct MapView: UIViewRepresentable {
@Binding var mapSelected: Int
@Binding var showDetails: Bool // I WANT TO TOGGLE THIS WHEN CALLOUT ACCESSORY IS TAPPED
@Binding var location: Location
@Binding var previousLocation: Location
@Binding var autoZoom: Bool
@Binding var autoZoomLevel: Int
class Coordinator: NSObject, MKMapViewDelegate {
@Binding var showDetails: Bool
init(showDetails: Binding<Bool>) {
_showDetails = showDetails
}
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
guard let coordinates = view.annotation?.coordinate else { return }
let span = mapView.region.span
let region = MKCoordinateRegion(center: coordinates, span: span)
mapView.setRegion(region, animated: true)
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
guard let annotation = annotation as? LocationAnnotation else { return nil }
let identifier = "Annotation"
var annotationView: MKMarkerAnnotationView? = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKMarkerAnnotationView
if annotationView == nil {
annotationView = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: identifier)
annotationView?.markerTintColor = UIColor(hex: "#00b4ffff")
annotationView?.animatesWhenAdded = true
annotationView?.canShowCallout = true
annotationView?.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
} else {
annotationView?.annotation = annotation
}
return annotationView
}
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
guard let loc = view.annotation as? LocationAnnotation else {
print("sorry")
return
}
print(self.showDetails) // true, false, true, false, ...
self.showDetails.toggle() // THIS DOES TOGGLE, BUT THE VALUE IS NOT OBSERVED BY THE PARENT VIEW
}
}
func makeCoordinator() -> Coordinator {
return Coordinator(showDetails: $showDetails)
}
func makeUIView(context: Context) -> MKMapView {
let map = MKMapView()
map.delegate = context.coordinator
return map
}
func updateUIView(_ uiView: MKMapView, context: Context) {
switch mapSelected {
case 0:
uiView.mapType = .standard
default:
uiView.mapType = .hybrid
}
let currentRegion = uiView.region // get the current region
var span: MKCoordinateSpan
var center: CLLocationCoordinate2D
var newRegion: MKCoordinateRegion
if currentRegion.span.latitudeDelta == 90.0 && currentRegion.span.longitudeDelta == 180.0 { // INITIAL
span = MKCoordinateSpan(latitudeDelta: 18.0, longitudeDelta: 18.0)
center = CLLocationCoordinate2D(latitude: 54.5, longitude: -110)
newRegion = MKCoordinateRegion(center: center, span: span)
uiView.setRegion(newRegion, animated: true)
}
updateAnnotations(from: uiView)
}
// ...
}
What I expect is that when the callout accessory is tapped, showDetails is toggled (which it is), but no effect is seen in the parent view—the sheet is not presented. Seems that the binding is not publishing its new state.
What am I missing / doing wrong? I find integrating UIKit with SwiftUI to be easy, then hard, then easy, then impossible. Help please!