在视图更新时在SwiftUI中使用WebKit隐藏键盘

时间:2020-01-04 01:36:56

标签: keyboard webkit swiftui wkwebview uikeyboard

我已经创建了一个最小的可重现性示例,用于说明我所面临的这个问题。

首先,我在WKWebView中创建了一个UIViewRepresentable,供SwiftUI使用。然后,我设置了WKUserContentControllerWKWebViewConfiguration,以便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
            }()
        )
    }
}

1 个答案:

答案 0 :(得分:1)

我建议(如我在这种情况下看到的最简单)将处理事件更改为

textarea.onblur = () =>
    webkit.messageHandlers.main.postMessage(textarea.value)

否则,需要进行复杂的重构,以使WK *实体远离SwiftUI可表示的包装器,或者更改模型以避免使用@State或任何导致视图重建的东西,或者两者都保留。