SwiftUI协调器未更新包含视图的属性

时间:2019-11-12 16:36:37

标签: swift swiftui

因此,我将WKWebView包装在UIViewRepresentable中,并构建了一个协调器,以便访问其导航委托的功能。在webView(_:didFinish:)函数中,我试图更新视图的didFinishLoading变量。如果我在分配后立即打印,它将打印true-预期的行为。但是,在父视图中,当我调用getHTML函数时,即使我等到WKWebView完全加载后,它也会打印false。 这是代码:

import SwiftUI
import WebKit

struct WebView: UIViewRepresentable {
    @Binding var link: String

    init(link: Binding<String>) {
        self._link = link
    }

    private var didFinishLoading: Bool = false

    let webView = WKWebView()

    func makeUIView(context: UIViewRepresentableContext<WebView>) -> WKWebView {
        self.webView.load(URLRequest(url: URL(string: self.link)!))
        self.webView.navigationDelegate = context.coordinator
        return self.webView
    }

    func updateUIView(_ uiView: WKWebView, context: UIViewRepresentableContext<WebView>) {
        return
    }

    class Coordinator: NSObject, WKNavigationDelegate {
        private var webView: WebView

        init(_ webView: WebView) {
            self.webView = webView
        }

        func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
            print("WebView: navigation finished")
            self.webView.didFinishLoading = true
        }
    }

    func makeCoordinator() -> WebView.Coordinator {
        Coordinator(self)
    }

    func getHTML(completionHandler: @escaping (Any?) -> ()) {
        print(self.didFinishLoading)
        if (self.didFinishLoading) {
            self.webView.evaluateJavaScript(
                """
                document.documentElement.outerHTML.toString()
                """
            ) { html, error in
                    if error != nil {
                        print("WebView error: \(error!)")
                        completionHandler(nil)
                    } else {
                        completionHandler(html)
                    }
            }
        }
    }
}

struct WebView_Previews: PreviewProvider {
    @State static var link = "https://apple.com"
    static var previews: some View {
        WebView(link: $link)
    }
}

1 个答案:

答案 0 :(得分:3)

这是您的代码,为演示做了一些修改,使用的ObservableObject视图模型实例保存了您的加载状态。

import SwiftUI
import WebKit
import Combine

class WebViewModel: ObservableObject {
    @Published var link: String
    @Published var didFinishLoading: Bool = false

    init (link: String) {
        self.link = link
    }
}

struct WebView: UIViewRepresentable {
    @ObservedObject var viewModel: WebViewModel

    let webView = WKWebView()

    func makeUIView(context: UIViewRepresentableContext<WebView>) -> WKWebView {
        self.webView.navigationDelegate = context.coordinator
        if let url = URL(string: viewModel.link) {
            self.webView.load(URLRequest(url: url))
        }
        return self.webView
    }

    func updateUIView(_ uiView: WKWebView, context: UIViewRepresentableContext<WebView>) {
        return
    }

    class Coordinator: NSObject, WKNavigationDelegate {
        private var viewModel: WebViewModel

        init(_ viewModel: WebViewModel) {
            self.viewModel = viewModel
        }

        func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
            print("WebView: navigation finished")
            self.viewModel.didFinishLoading = true
        }
    }

    func makeCoordinator() -> WebView.Coordinator {
        Coordinator(viewModel)
    }

}

struct WebViewContentView: View {
    @ObservedObject var model = WebViewModel(link: "https://apple.com")

    var body: some View {
        VStack {
            TextField("", text: $model.link)
            WebView(viewModel: model)
            if model.didFinishLoading {
                Text("Finished loading")
                    .foregroundColor(Color.red)
            }
        }
    }
}

struct WebView_Previews: PreviewProvider {
    static var previews: some View {
        WebViewContentView()
    }
}