在SwiftUI中控制嵌套UIView的惯用方式是什么

时间:2019-10-04 16:23:03

标签: ios swift wkwebview swiftui

我想在SwiftUI视图层次结构中显示WKWebView,并且想使用SwiftUI中实现的按钮控制WKWebView。

我可以通过创建一个实现WebView并包装UIViewRepresentable的SwiftUI WKWebView类来实现此目的,

struct WebView: UIViewRepresentable {

  func makeUIView(context: UIViewRepresentableContext<WebView>) -> WKWebView {
    return WKWebView(frame: .zero)
  }

  func updateUIView(_ uiView: WKWebView, context: UIViewRepresentableContext<WebView>) {
    // Update WKWebView here if necessary
  }
}

...然后按如下所述使用它...


struct BrowserView: View {
  var body: some View {
    VStack {
      WebView()

      // Footer
      HStack {
        Button(action: {
          // When this is called, I want to somehow call .goBack()
          // on the WKWebView.
        }) {
          Image(systemName: "chevron.left")
        }

        ...
      } // HStack
    } // VStack
  }
}

当用户点击按钮时,我想以某种方式调用goBack上的WKWebView。我该如何在SwiftUI中惯用的方式?

我认为这种方法要么很脆弱,要么不是惯用的SwiftUI ...

  • 表示用户在绑定中单击“返回”的次数。让WebView监听该绑定,并在绑定增加时移回。

  • BrowserView创建了一个名为MutableWebViewAPI的对象,并将其传递给WebViewWebView侦听此对象,以便当BrowserView调用类似MutableWebViewAPI.goBack()的对象时,WebView会执行相同的操作。

1 个答案:

答案 0 :(得分:1)

我认为最好的方法是通过在父视图上创建一个PassthroughSubject然后订阅孩子WebView中的事件来利用Combine的功能。

首先,在您的UIViewReprsentable中创建一个结构,以捕获要发送到WebView的可用事件:

struct WebView: UIViewReprsentable {

    enum WebEvent {
        case back
        case forward
    }

    let eventPublisher: AnyPublisher<WebEvent, Never>

    init(eventPublisher: AnyPublisher<WebEvent, Never>) {
        self.eventPublisher = eventPublisher

        eventPublisher.sink { event in
            // forward the appropriate event to your underlying WKWebView
        }
    }
}

接下来,在您的父母中,创建PassthroughSubject来创建这些事件。

struct ParentView: View {
    private let eventSender = PassthroughSubject<WebView.WebEvent, Never>()

    var body: some View {
        VStack {
            Button("Back") {
                self.eventSender.send(.back)
            }
            Button("Forward") {
                self.eventSender.send(.forward)
            }

            WebView(eventPublisher: eventSender.eraseToAnyPublisher())
        }
    }
}