在 SwiftUI 中使用 WebKit 在视图更新时隐藏键盘
Using WebKit in SwiftUI hides keyboard when view updates
我已经为我面临的这个问题创建了一个最小的可重现示例。
首先,我在 UIViewRepresentable
中创建了一个 WKWebView
以与 SwiftUI 一起使用。然后,我设置了一个 WKUserContentController
和一个 WKWebViewConfiguration
,这样 WKWebView
就可以将消息发送到本机代码。在这种情况下,我有一个 <textarea>
在输入时发送它的 value
。
通过 WebKit 发送的值被分配给一个 @State
变量,该变量导致视图更新。不幸的是,每当视图更新时,WKWebView
都会被取消选择。我该如何解决这个问题? WKWebView
需要保持选中状态,直到用户有意选择隐藏键盘。
这是正在发生的事情的一个最小示例:
import SwiftUI
import WebKit
struct WebView: UIViewRepresentable {
let html: String
let configuration: WKWebViewConfiguration
func makeUIView(context: Context) -> WKWebView {
.init(frame: .zero, configuration: configuration)
}
func updateUIView(_ webView: WKWebView, context: Context) {
webView.loadHTMLString(html, baseURL: nil)
}
}
struct ContentView: View {
final class Coordinator: NSObject, WKScriptMessageHandler {
@Binding var text: String
init(text: Binding<String>) {
_text = text
}
func userContentController(
_ userContentController: WKUserContentController,
didReceive message: WKScriptMessage
) {
guard let text = message.body as? String else { return }
self.text = text
}
}
@State var text = ""
var body: some View {
WebView(
html: """
<!DOCTYPE html>
<html>
<body>
<textarea>\(text)</textarea>
<script>
const textarea = document.querySelector('textarea')
textarea.oninput = () =>
webkit.messageHandlers.main.postMessage(textarea.value)
</script>
</body>
</html>
""",
configuration: {
let userContentController = WKUserContentController()
userContentController.add(Coordinator(text: $text), name: "main")
let configuration = WKWebViewConfiguration()
configuration.userContentController = userContentController
return configuration
}()
)
}
}
我建议(我认为在这种情况下最简单)将处理事件更改为
textarea.onblur = () =>
webkit.messageHandlers.main.postMessage(textarea.value)
否则,需要进行复杂的重构以远离 SwiftUI 可表示包装器中的 WK* 实体,或更改模型以避免使用 @State
或任何导致视图重建的东西,或两者兼而有之。
我已经为我面临的这个问题创建了一个最小的可重现示例。
首先,我在 UIViewRepresentable
中创建了一个 WKWebView
以与 SwiftUI 一起使用。然后,我设置了一个 WKUserContentController
和一个 WKWebViewConfiguration
,这样 WKWebView
就可以将消息发送到本机代码。在这种情况下,我有一个 <textarea>
在输入时发送它的 value
。
通过 WebKit 发送的值被分配给一个 @State
变量,该变量导致视图更新。不幸的是,每当视图更新时,WKWebView
都会被取消选择。我该如何解决这个问题? WKWebView
需要保持选中状态,直到用户有意选择隐藏键盘。
这是正在发生的事情的一个最小示例:
import SwiftUI
import WebKit
struct WebView: UIViewRepresentable {
let html: String
let configuration: WKWebViewConfiguration
func makeUIView(context: Context) -> WKWebView {
.init(frame: .zero, configuration: configuration)
}
func updateUIView(_ webView: WKWebView, context: Context) {
webView.loadHTMLString(html, baseURL: nil)
}
}
struct ContentView: View {
final class Coordinator: NSObject, WKScriptMessageHandler {
@Binding var text: String
init(text: Binding<String>) {
_text = text
}
func userContentController(
_ userContentController: WKUserContentController,
didReceive message: WKScriptMessage
) {
guard let text = message.body as? String else { return }
self.text = text
}
}
@State var text = ""
var body: some View {
WebView(
html: """
<!DOCTYPE html>
<html>
<body>
<textarea>\(text)</textarea>
<script>
const textarea = document.querySelector('textarea')
textarea.oninput = () =>
webkit.messageHandlers.main.postMessage(textarea.value)
</script>
</body>
</html>
""",
configuration: {
let userContentController = WKUserContentController()
userContentController.add(Coordinator(text: $text), name: "main")
let configuration = WKWebViewConfiguration()
configuration.userContentController = userContentController
return configuration
}()
)
}
}
我建议(我认为在这种情况下最简单)将处理事件更改为
textarea.onblur = () =>
webkit.messageHandlers.main.postMessage(textarea.value)
否则,需要进行复杂的重构以远离 SwiftUI 可表示包装器中的 WK* 实体,或更改模型以避免使用 @State
或任何导致视图重建的东西,或两者兼而有之。