【问题标题】:What's the idiomatic way to control a nested UIView in SwiftUI在 SwiftUI 中控制嵌套 UIView 的惯用方式是什么
【发布时间】:2020-02-03 00:12:45
【问题描述】:

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

我可以通过创建一个实现 UIViewRepresentable 并包装 WKWebView 的 SwiftUI WebView 类来做到这一点,就像这样......

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
  }
}

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

我认为我认为很脆弱或不是惯用的 SwiftUI 的方法...

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

  • BrowserView 创建一个名为MutableWebViewAPI 的对象,并在构造时将其传递给WebViewWebView 监听这个对象,这样当BrowserView 调用类似MutableWebViewAPI.goBack() 的东西时,WebView 也会这样做。

【问题讨论】:

    标签: ios swift wkwebview swiftui


    【解决方案1】:

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

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

    struct WebView: UIViewRepresentable {
    
        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())
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-09
      • 2020-01-22
      • 1970-01-01
      • 1970-01-01
      • 2011-05-28
      • 1970-01-01
      • 2020-09-01
      • 2013-01-03
      相关资源
      最近更新 更多