从子级向父级发布消息

时间:2019-12-16 22:53:49

标签: swiftui combine

我正试图将这个问题的答案抛在脑后:

What's the idiomatic way to control a nested UIView in SwiftUI

并从子(WebView)发布事件并订阅ParentView

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

WebView(eventSender: eventSender)

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

有人有一个优雅的解决方案吗?

通常我会使用@EnvironmentObject,但这些似乎不能与UIViewRepresentable一起使用。

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

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

我想关闭此视图(导航导航插入时导航回到显示之前的状态)。

3 个答案:

答案 0 :(得分:1)

如果您希望从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)
    }

  }

}

答案 1 :(得分:0)

您可以构建自己的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

答案 2 :(得分:0)

我在这里回答了这个问题:How to access content view's elements later in SwiftUI?

(我也是您引用的帖子中另一个被接受的答案)

您基本上想设置一个传入的处理程序,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
  }
}