SwiftUI 协调器不更新包含视图的属性 [英] SwiftUI coordinator not updating the containing view's property

查看:17
本文介绍了SwiftUI 协调器不更新包含视图的属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

So I've wrapped WKWebView in an UIViewRepresentable and built a coordinator in order to access its navigation delegate's functions. In the webView(_:didFinish:) function I am trying to update the view's didFinishLoading variable. If I print right after assigning, it prints true - the expected behavior. But, in the parent view, when I call the getHTML function, it prints false - even if I wait until the WKWebView is fully loaded. Here is the code:

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

推荐答案

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

Here is your code, a bit modified for demo, with used view model instance of ObservableObject holding your loading state.

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

这篇关于SwiftUI 协调器不更新包含视图的属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆