gpt4 book ai didi

swift - 如何在 swiftUI 中以线性样式 ProgressView 显示 WKWebView 的估计进度?

转载 作者:行者123 更新时间:2023-12-02 01:51:25 24 4
gpt4 key购买 nike

我尝试就此事搜索数周,但找不到在 SwiftUI 中实现的任何帮助。大多数答案都是针对 UIKit 的。

struct ContentView: View {
@State private var progress: Double = 0.0

var body: some View {
VStack {
WebView()

ProgressView(value: progress)
.progressViewStyle(.linear)
}
}
}

struct WebView: UIViewRepresentable {
func makeUIView(context: Context) -> WKWebView {
let webView = WKWebView()
webView.load(URLRequest(url: URL(string: "https://www.apple.com")!))
return webView
}

func updateUIView(_ uiView: WKWebView, context: Context) {

}
}

最佳答案

因为您正在使用 UIViewRepresentable 来包装 WKWebView,所以您需要使用 UIKit 解决方案。

我们可以使用键值观察 (KVO) 跟踪 WKWebViewestimatedProgress。为此,我们需要向我们的 WebView 添加一个协调器。

仅仅添加协调器是不够的,我们需要一种方法将值从 UIViewRepresentable 传递回 View。我们可以使用 @Binding 或闭包来完成此操作,但这会在更新 View 时导致以下错误:

Warning: Modifying state during view update, this will cause undefined behavior.

“hacky”解决方案是使用 DispatchQueue.main.async 包装绑定(bind)的 progress 变量的设置,但这不是一个好的解决方案。

解决此问题的更好方法是创建一个符合 ObservableObject 的简单 ViewModel。

这给出了以下代码:

struct ContentView: View {
@StateObject var viewModel = WebView.ProgressViewModel(progress: 0.0)

var body: some View {
VStack {
WebView(url: URL(string: "https://www.apple.com")!, viewModel: viewModel)

ProgressView(value: viewModel.progress)
.progressViewStyle(.linear)
}
}
}

ContentView 现在持有对 ProgressViewModel 的引用,它与 URL 一起传递给 WebViewProgressViewProgressViewModel 传递 @Published 进度。

struct WebView: UIViewRepresentable {

let url: URL
@ObservedObject var viewModel: ProgressViewModel

private let webView = WKWebView()

func makeUIView(context: Context) -> WKWebView {
webView.load(URLRequest(url: url))
return webView
}

func updateUIView(_ uiView: WKWebView, context: Context) {

}
}

除了我们传递的是 URLProgressViewModel 之外,这与您的 UIViewRepresentable 没有太大区别。我们还在 makeUIView 中提出了 webView 的初始化,这样我们就可以在 Coordinator 中访问它。

extension WebView {

func makeCoordinator() -> Coordinator {
Coordinator(self, viewModel: viewModel)
}

class Coordinator: NSObject {
private var parent: WebView
private var viewModel: ProgressViewModel
private var observer: NSKeyValueObservation?

init(_ parent: WebView, viewModel: ProgressViewModel) {
self.parent = parent
self.viewModel = viewModel
super.init()

observer = self.parent.webView.observe(\.estimatedProgress) { [weak self] webView, _ in
guard let self = self else { return }
self.parent.viewModel.progress = webView.estimatedProgress
}
}

deinit {
observer = nil
}
}
}

WebView 上的这个扩展创建了协调器,它继承自 NSObject。它包含对父级、WebView 和 viewModel 的引用。我们在初始化程序中设置了一个 KVO 观察器,用于观察 webView 上的 estimatedProgress,这使我们能够更新 viewModel 上的进度值。

extension WebView {
class ProgressViewModel: ObservableObject {
@Published var progress: Double = 0.0

init (progress: Double) {
self.progress = progress
}
}
}

最后,这是将 UIViewRepresentableView 联系在一起的 ProgressViewModel

你可以看到它的视频here

关于swift - 如何在 swiftUI 中以线性样式 ProgressView 显示 WKWebView 的估计进度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70300114/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com