如何在WKWebView中添加一个活动指示器,在网页加载时显示该指示器,并在加载完成后消失?
我查看了一些旧帖子,但无法弄清楚如何在SwiftUI中实现 请参见下面旧解决方案的链接 如何向WKWebView添加活动指示器(Swift 3)
如何在WKWebView中添加一个活动指示器,在网页加载时显示该指示器,并在加载完成后消失?
我查看了一些旧帖子,但无法弄清楚如何在SwiftUI中实现 请参见下面旧解决方案的链接 如何向WKWebView添加活动指示器(Swift 3)
使用UIViewRepresentable
来创建一个UIActivityIndicatorView:
通过调用
startAnimating()
和stopAnimating()
方法来控制活动指示器的动画。要在动画停止时自动隐藏活动指示器,请将hidesWhenStopped
属性设置为true。可以使用
color
属性来设置活动指示器的颜色。
struct ActivityIndicatorView: UIViewRepresentable {
@Binding var isAnimating: Bool
let style: UIActivityIndicatorView.Style
func makeUIView(context: UIViewRepresentableContext<ActivityIndicatorView>) -> UIActivityIndicatorView {
return UIActivityIndicatorView(style: style)
}
func updateUIView(_ uiView: UIActivityIndicatorView, context: UIViewRepresentableContext<ActivityIndicatorView>) {
isAnimating ? uiView.startAnimating() : uiView.stopAnimating()
}
}
创建一个LoadingView
以便您可以将其包装在视图周围:struct LoadingView<Content>: View where Content: View {
@Binding var isShowing: Bool
var content: () -> Content
var body: some View {
GeometryReader { geometry in
ZStack(alignment: .center) {
self.content()
.disabled(self.isShowing)
.blur(radius: self.isShowing ? 3 : 0)
VStack {
Text("Loading...")
ActivityIndicatorView(isAnimating: .constant(true), style: .large)
}
.frame(width: geometry.size.width / 2, height: geometry.size.height / 5)
.background(Color.secondary.colorInvert())
.foregroundColor(Color.red)
.cornerRadius(20)
.opacity(self.isShowing ? 1 : 0)
}
}
}
}
如果您希望能够更新 LoadingView(...)
的状态,则需要引入一个从 ObservableObject
继承的视图模型:
根据这个答案:https://stackoverflow.com/a/58825642/264802
class WebViewModel: ObservableObject {
@Published var url: String
@Published var isLoading: Bool = true
init (url: String) {
self.url = url
}
}
struct WebView: UIViewRepresentable {
@ObservedObject var viewModel: WebViewModel
let webView = WKWebView()
func makeCoordinator() -> Coordinator {
Coordinator(self.viewModel)
}
class Coordinator: NSObject, WKNavigationDelegate {
private var viewModel: WebViewModel
init(_ viewModel: WebViewModel) {
self.viewModel = viewModel
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
self.viewModel.isLoading = false
}
}
func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<WebView>) { }
func makeUIView(context: Context) -> UIView {
self.webView.navigationDelegate = context.coordinator
if let url = URL(string: self.viewModel.url) {
self.webView.load(URLRequest(url: url))
}
return self.webView
}
}
那么,在您的视图中使用它,您需要执行以下操作:
struct ContentView: View {
@StateObject var model = WebViewModel(url: "http://www.google.com")
var body: some View {
LoadingView(isShowing: self.$model.isLoading) {
WebView(viewModel: self.model)
}
}
}
WKWebview
加载完成后关闭活动指示器。 - fulvio在我的项目中,我使用三个步骤来完成它。
第一步:创建一个加载视图
import SwiftUI
import UIKit
struct ActivityIndicatorView: UIViewRepresentable {
@Binding var isAnimating: Bool
let style: UIActivityIndicatorView.Style
func makeUIView(context: Context) -> UIActivityIndicatorView {
return UIActivityIndicatorView(style: style)
}
func updateUIView(_ uiView: UIActivityIndicatorView, context: Context) {
isAnimating ? uiView.startAnimating() : uiView.stopAnimating()
}
}
// Main View
struct LoadingView<Content>: View where Content: View {
@Binding var isShowing: Bool
let message: String
var content: () -> Content
var body: some View {
GeometryReader { geometry in
ZStack(alignment: .center) {
self.content()
.disabled(self.isShowing)
.blur(radius: self.isShowing ? 3 : 0)
VStack {
Text(self.message)
.bold()
ActivityIndicatorView(isAnimating: .constant(true), style: .large)
}
.frame(width: geometry.size.width / 2,
height: geometry.size.height / 5)
.background(Color.secondary.colorInvert())
.foregroundColor(Color.primary)
.cornerRadius(20)
.opacity(self.isShowing ? 1 : 0)
}
}
}
}
// Mark: Testing
struct LoadingIndicator: View {
var body: some View {
LoadingView(isShowing: .constant(true), message: "Loading...") {
NavigationView {
List(["1", "2", "3", "4", "5"], id: \.self) { row in
Text(row)
}.navigationBarTitle(Text("A List"), displayMode: .large)
}
}
}
}
struct ActivityIndicatorView_Previews: PreviewProvider {
static var previews: some View {
LoadingIndicator()
}
}
步骤2:创建 WebView 和 WebViewModel
import SwiftUI
import WebKit
class WebViewModel: ObservableObject {
@Published var isLoading: Bool = false
}
struct WebView: UIViewRepresentable {
@ObservedObject var webViewModel: WebViewModel
let urlString: String
func makeUIView(context: Context) -> WKWebView {
let wkWebView = WKWebView()
if let url = URL(string: urlString) {
let urlRequest = URLRequest(url: url)
wkWebView.load(urlRequest)
}
return wkWebView
}
func updateUIView(_ wkWebView: WKWebView, context: Context) {
// do nothing
}
class Coordinator: NSObject, WKNavigationDelegate {
let webViewModel: WebViewModel
init(_ webViewModel: WebViewModel) {
self.webViewModel = webViewModel
}
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
webViewModel.isLoading = true
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
webViewModel.isLoading = false
}
}
func makeCoordinator() -> WebView.Coordinator {
Coordinator(webViewModel)
}
}
struct WebView_Previews: PreviewProvider {
static var previews: some View {
WebView(webViewModel: WebViewModel(),
urlString: "https://instagram.com/mahmudahsan/")
}
}
步骤3:在您的主视图中使用以下代码来显示指示器和Web视图
ZStack {
WebView(webViewModel: webViewModel, urlString: "http://ithinkdiff.net")
.frame(height: 1000)
if webViewModel.isLoading {
LoadingView(isShowing: .constant(true), message: "Loading...") {
EmptyView()
}
}
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { self.webViewModel.isLoading = false }
。 - Ashley Vaz
func webView(WKWebView, didFinish: WKNavigation!)
。在这里,您可以使用UIActivityIndicator
的stopAnimating()
方法。 - palme