在 SwiftUI 中控制嵌套 UIView 的惯用方法是什么
What's the idiomatic way to control a nested UIView in SwiftUI
我想在 SwiftUI 视图层次结构中显示 WKWebView,并且我想使用 SwiftUI 中实现的按钮来控制 WKWebView。
我可以通过创建一个实现 UIViewRepresentable
并包装 WKWebView
的 SwiftUI WebView
class 来做到这一点,就像这样...
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 的方法...
表示用户在绑定中单击 "Back" 的次数。让 WebView 监听该绑定并在该绑定增加时返回。
让 BrowserView
创建一个类似于 MutableWebViewAPI
的对象,并在构建时将其传递给 WebView
。 WebView
侦听此对象,因此当 BrowserView
调用类似 MutableWebViewAPI.goBack()
的内容时,WebView
会执行相同的操作。
我认为最好的方法是通过在您的父视图上创建一个 PassthroughSubject
来利用 Combine 的强大功能,然后在您的子视图中订阅事件 WebView
。
首先,在您的 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())
}
}
}
我想在 SwiftUI 视图层次结构中显示 WKWebView,并且我想使用 SwiftUI 中实现的按钮来控制 WKWebView。
我可以通过创建一个实现 UIViewRepresentable
并包装 WKWebView
的 SwiftUI WebView
class 来做到这一点,就像这样...
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 的方法...
表示用户在绑定中单击 "Back" 的次数。让 WebView 监听该绑定并在该绑定增加时返回。
让
BrowserView
创建一个类似于MutableWebViewAPI
的对象,并在构建时将其传递给WebView
。WebView
侦听此对象,因此当BrowserView
调用类似MutableWebViewAPI.goBack()
的内容时,WebView
会执行相同的操作。
我认为最好的方法是通过在您的父视图上创建一个 PassthroughSubject
来利用 Combine 的强大功能,然后在您的子视图中订阅事件 WebView
。
首先,在您的 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())
}
}
}