如何从 MKMapView didSelect 注释更新封装的 SwiftUI 视图

Posted

技术标签:

【中文标题】如何从 MKMapView didSelect 注释更新封装的 SwiftUI 视图【英文标题】:How to update encapsulating SwiftUI View from MKMapView didSelect annotation 【发布时间】:2020-10-18 22:37:32 【问题描述】:

从 MKMapKit didSelect 注解委托中向封装的 SwiftUI 视图推送更新的适当方法是什么?

struct CompoundView: View 
  @State private var selected: MKAnnotation?
  
  var body: some View 
    ZStack 
      MapView(annotations: annotations, selected: $selected)
      if let selected = selected 
        PopUpView(selected)
      
    
  

MapView 被实现为带有代表的UIViewRepresentable

func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) 
  subject.selected = view.annotation // subject is the controller's reference to the MapView wrapping MKMapView 

将回调传递给更新 CompoundView 状态的委托会导致 XCode 触发 Modifying state during view update, this will cause undefined behavior. 它还可以防止 MKMapView 中的注释引脚被明显选择(引脚图标在第一次不会增长被点击)。

同样,将绑定从CompoundView 传递到MapView 似乎是有问题的,因为点击时图钉图标不增长的问题仍然存在。我假设由于状态更改而重建父视图。

我尝试将委托逻辑包装在 DispatchQueue.main.async 调用中,但没有成功,此时我只是在猜测。

是否有一种首选方法可以从 MKMapView 委托调用中将信息反馈给父视图,这样我们既不在视图更新中,也不会阻止地图注释在点击时正常动画?

【问题讨论】:

【参考方案1】:

编辑:事实证明,我在选择时没有动画的注释问题的根源在于,每当视图更新时,我都会不断刷新注释。在makeUIView 中添加注释并将updateUIView 留空解决了很多奇怪的交互。

func updateUIView(_ map: MKMapView, context: Context) 
  map.removeAnnotations(map.annotations)
  map.addAnnotations(annotations)

通过使用ObservableObject,我能够让两个视图都发挥得很好。该对象将@Published 父视图订阅的选定注释@ObservedObject(或@StateObject)。然后地图视图从委托调用中更新了可观察对象的注释类成员。请注意,地图视图不会将对象标记为@ObservedObject,因为当模型发生更改时地图视图不应更新(这会导致地图注释出现错误并且在选择和取消选择时没有动画)。

【讨论】:

以上是关于如何从 MKMapView didSelect 注释更新封装的 SwiftUI 视图的主要内容,如果未能解决你的问题,请参考以下文章

如何使 MKMapView 从顶部进入

如何禁用为 UITableViewCell 的某些部分调用 DidSelect?

如何在表格视图的 didSelect 上显示弹出框

在 Swift 3 中使用 didSelect 和 navigationController 在没有情节提要的情况下在 TableViewControllers 之间传递数据

在 DidSelect 上,如何返回整个核心数据记录? (迅速)

tableView didSelect 单元格不起作用