在 calloutAccessoryControlTapped 时更改传入 "MapView: UIViewRepresentable" 的 BindableObject 的值
Changing the value of a BindableObject passed into a "MapView: UIViewRepresentable" when calloutAccessoryControlTapped
构建一个主要是 SwiftUI 的应用程序...我正在尝试将父视图中 BindableObject 的值连接(绑定)到 MapKit 子视图,这样当点击注释(标注附件)时(注释标签上的小 (i) 按钮...
...它将 $showDetails 的值更改为 true,它连接到 "sheet(isPresented: $showDetails...)" 进一步向上的视图层次结构,然后显示模态:
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)
}
// ...
}
我期望的是,当点击 callout 附件时,showDetails 会切换(确实如此),但在父视图中看不到任何效果 — sheet 未显示。似乎绑定没有发布其新状态。
我错过了什么/做错了什么?我发现将 UIKit 与 SwiftUI 集成先是简单,然后是困难,然后是简单,然后是不可能。请帮忙!
事实证明,我看错地方了。问题不在于上面的代码(100% 没问题),而在于 应该 一直在监听 showDetails[= 的更改值的容器视图35=],但不是因为我将 showDetails 传递给它的方式,例如
ContentView.swift
Footer(search: search,
locationStore: self.locationStore,
searchCoordinates: self.searchCoordinates,
showDetails: self.showDetails) // NOT PASSED AS A BINDING...
Footer.swift
struct Footer: View {
@EnvironmentObject var settingsStore: SettingsStore
@ObservedObject var search: SearchTerm
@ObservedObject var locationStore: LocationStore
@ObservedObject var searchCoordinates: SearchCoordinates
@State var showDetails: Bool // DECLARE LOCAL STATE, WILL NOT BE AWARE OF CHANGE TO showDetails FROM MapView
非常简单的修复:
ContentView.swift
Footer(search: search,
locationStore: self.locationStore,
searchCoordinates: self.searchCoordinates,
showDetails: self.$showDetails)
Footer.swift
struct Footer: View {
@EnvironmentObject var settingsStore: SettingsStore
@ObservedObject var search: SearchTerm
@ObservedObject var locationStore: LocationStore
@ObservedObject var searchCoordinates: SearchCoordinates
@Binding var showDetails: Bool
当不小心对传入变量使用错误的 属性 包装器时,感觉像这样的错误很容易在 SwiftUI 中遇到(顺便说一句,这很棒)。编译器不会警告您,也没有运行时错误,只是……什么也没有发生。而你和我一样,可能倾向于追逐红色鲱鱼a.k.a。完美的代码。
构建一个主要是 SwiftUI 的应用程序...我正在尝试将父视图中 BindableObject 的值连接(绑定)到 MapKit 子视图,这样当点击注释(标注附件)时(注释标签上的小 (i) 按钮...
...它将 $showDetails 的值更改为 true,它连接到 "sheet(isPresented: $showDetails...)" 进一步向上的视图层次结构,然后显示模态:
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)
}
// ...
}
我期望的是,当点击 callout 附件时,showDetails 会切换(确实如此),但在父视图中看不到任何效果 — sheet 未显示。似乎绑定没有发布其新状态。
我错过了什么/做错了什么?我发现将 UIKit 与 SwiftUI 集成先是简单,然后是困难,然后是简单,然后是不可能。请帮忙!
事实证明,我看错地方了。问题不在于上面的代码(100% 没问题),而在于 应该 一直在监听 showDetails[= 的更改值的容器视图35=],但不是因为我将 showDetails 传递给它的方式,例如
ContentView.swift
Footer(search: search,
locationStore: self.locationStore,
searchCoordinates: self.searchCoordinates,
showDetails: self.showDetails) // NOT PASSED AS A BINDING...
Footer.swift
struct Footer: View {
@EnvironmentObject var settingsStore: SettingsStore
@ObservedObject var search: SearchTerm
@ObservedObject var locationStore: LocationStore
@ObservedObject var searchCoordinates: SearchCoordinates
@State var showDetails: Bool // DECLARE LOCAL STATE, WILL NOT BE AWARE OF CHANGE TO showDetails FROM MapView
非常简单的修复:
ContentView.swift
Footer(search: search,
locationStore: self.locationStore,
searchCoordinates: self.searchCoordinates,
showDetails: self.$showDetails)
Footer.swift
struct Footer: View {
@EnvironmentObject var settingsStore: SettingsStore
@ObservedObject var search: SearchTerm
@ObservedObject var locationStore: LocationStore
@ObservedObject var searchCoordinates: SearchCoordinates
@Binding var showDetails: Bool
当不小心对传入变量使用错误的 属性 包装器时,感觉像这样的错误很容易在 SwiftUI 中遇到(顺便说一句,这很棒)。编译器不会警告您,也没有运行时错误,只是……什么也没有发生。而你和我一样,可能倾向于追逐红色鲱鱼a.k.a。完美的代码。