ThatConfusedDev
ThatConfusedDev

Reputation: 1

How can I add an ActivtyIndicator to this WebView that shows when a website is loading?

How can add an ActivityIndicator (spinning wheel) to this WebView when it's loading a website?

Here's the code for the WebView:

import Foundation
import SwiftUI
import WebKit

struct WebView : UIViewRepresentable {
    
    var url: String
    
    func makeUIView(context: Context) -> WKWebView {
        
        guard let url = URL(string: self.url) else {
            return WKWebView()
        }
        
        let request = URLRequest(url: url)
        let wkWebView = WKWebView()
        wkWebView.load(request)
        return wkWebView
    }

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

And here's the code to show the WebView in another view and tell it what URL to load:

WebView(url: "https://www.google.com")

Thanks!

EDIT: I have to be able to pass the URL as a string like shown above when calling the WebView in another view. That way I can easily tell the WebView what URL to load, and place two instances of WebView() together in a view showing different websites like so:

VStack {
WebView(url: "https://www.google.com")
WebView(url: "https://www.bing.com")
}

Upvotes: 0

Views: 912

Answers (2)

Bruce G
Bruce G

Reputation: 183

Thanks to Faizan for the excellent solution!

If you want to get rid of the frame logic (with hard-coded numbers), here's a rewrite using constraints to center the activity indicator. I've also set its color to .label so it's more light/dark mode friendly.

struct WebView: UIViewRepresentable {

    let url: URL

    var activityIndicator = UIActivityIndicatorView(style: .large)

    func makeUIView(context: Context) -> WKWebView {
        let webView = WKWebView()

        activityIndicator.translatesAutoresizingMaskIntoConstraints = false
        activityIndicator.color = .label

        webView.addSubview(activityIndicator)
        NSLayoutConstraint.activate([
            activityIndicator.centerXAnchor.constraint(equalTo: webView.centerXAnchor),
            activityIndicator.centerYAnchor.constraint(equalTo: webView.centerYAnchor)
        ])

        webView.navigationDelegate = context.coordinator

        return webView
    }

    func updateUIView(_ webView: WKWebView, context: Context) {
        activityIndicator.startAnimating()

        let request = URLRequest(url: url)
        webView.load(request)
    }

    func makeCoordinator() -> WebViewHelper {
        WebViewHelper(self)
    }

}

class WebViewHelper: NSObject, WKNavigationDelegate {

    let webView: WebView

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

    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        self.webView.activityIndicator.stopAnimating()
    }

    func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
        self.webView.activityIndicator.stopAnimating()
        print("error: \(error)")
    }

    func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
        self.webView.activityIndicator.stopAnimating()
        print("error: \(error)")
    }

}

Upvotes: 0

Faizan Yousaf
Faizan Yousaf

Reputation: 164

You can use the following code it contains "UIActivityIndicatorView" and is handled with "WKNavigationDelegate"

import WebKit
import SwiftUI

struct Webview: UIViewRepresentable {
let url: URL
var activityIndicator: UIActivityIndicatorView! = UIActivityIndicatorView(frame: CGRect(x: (UIScreen.main.bounds.width / 2) - 30, y: (UIScreen.main.bounds.height / 2) - 30, width: 60, height: 60))

func makeUIView(context: Context) -> UIView {
    let view = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height))
    let webview = WKWebView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height))
    webview.navigationDelegate = context.coordinator
    
    let request = URLRequest(url: self.url, cachePolicy: .returnCacheDataElseLoad)
    webview.load(request)
    
    view.addSubview(webview)
    activityIndicator.backgroundColor = UIColor.gray
    activityIndicator.startAnimating()
    activityIndicator.color = UIColor.white
    activityIndicator.layer.cornerRadius = 8
    activityIndicator.clipsToBounds = true
    
    view.addSubview(activityIndicator)
    return view
}

func updateUIView(_ webview: UIView, context: UIViewRepresentableContext<Webview>) {
}

func makeCoordinator() -> WebViewHelper {
    WebViewHelper(self)
}
}

class WebViewHelper: NSObject, WKNavigationDelegate {

var parent: Webview
init(_ parent: Webview) {
    self.parent = parent
    super.init()
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    parent.activityIndicator.isHidden = true
}

func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
    parent.activityIndicator.isHidden = true
    print("error: \(error)")
}

func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
    parent.activityIndicator.isHidden = true
    print("error \(error)")
}
}

Upvotes: 3

Related Questions