从 child 发布消息到 parent 查看

Publish a message from child to parent View

我正试图翻转这个问题的答案:

并发布来自 child (WebView) 的事件并订阅 ParentView

我可以在 WebView 的构造函数中传递 eventSender,例如:

WebView(eventSender: eventSender)

那么 WebView 应该可以发送事件,但是如何订阅 ParentView 中发布的事件?

谁有优雅的解决方案?

通常我会使用 @EnvironmentObject 但这些似乎不适用于 UIViewRepresentable

更新 - 我在这里创建了一个问题的要点:https://gist.github.com/mattlaver/45519a58de65a304b10acaee663b06a2

请注意,我的 childView 是 class,而不是结构,因为它需要从 NSObject 继承才能使用 navigationDelegate。

我想关闭此视图(在 navigationDelegate 启动时导航回到它显示之前)。

您可以构建自己的 Binding 并传递您需要的任何对象,@EnvironmentObject@ObservedObject

看起来 @FetchRequestUIViewRepresentable 中运行良好(如果您使用的是 CoreData

struct ContentView: View {
    @EnvironmentObject var store: Store<AppState, AppAction> 

    var body: some View {
        WebViewRepresentable(state: Binding<AppState>(get: { self.store.state }, set { _ in}))
    }
}

struct WebViewRepresentable: UIViewRepresentable {
      @Binding var state: AppState
      [...]
}

来源:https://gist.github.com/svanimpe/152e6539cd371a9ae0cfee42b374d7c4

我在这里回答了这个问题:

(我也是您所引用 post 的另一个已接受答案)

您基本上想要设置一个传入的处理程序,这是 SwiftUI 经常使用的一种方法(请参阅 TextField 各种事件的传入处理程序选项。)

struct WebViewRepresentable: UIViewRepresentable {
  let onEvent: (AppState) -> Void

  // not sure what events you're talking about, probably `WKWebView` specific so tailor this to those needs
  fun eventReceived(event: AppState) {
    self.onEvent(event)
  }

那么在你的父视图中:

var body: some View {
  WebViewRepresentable { event in
    // handle your event
  }
}

如果您希望从 UiViewRepresentable 传递状态,但您需要从协调器设置它,则绑定是可行的方法。例如:

struct WebView: UIViewRepresentable {

  @Binding var state: Int // this can be whatever type

  func makeUIView(context: UIViewRepresentableContext<WebView>) -> WKWebView {
    let uiView = WKWebView()
    uiView.navigationDelegate = context.coordinator
    self.state = 0
    return uiView
  }

  func updateUIView(_ uiView: WKWebView, context: UIViewRepresentableContext<WebView>) {
  }

  func makeCoordinator() -> WebView.Coordinator {
    Coordinator(view: self)
  }

  class Coordinator: NSObject, WKNavigationDelegate {

    let view: WebView

    init(view: WebView) {
      self.view = view
    }

    func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
      self.view.state = 1 // the binding will update the parent
      decisionHandler(.allow)
    }

  }

}