3

I have a basic list that displays a webview. I want to add an activity indicator that shows while the webpage is loading. this is the code that I've created.

import SwiftUI
import WebKit

struct WebView: UIViewRepresentable {
    var url: String

    // makeUIView func
    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
    }

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

}


struct WebView_Preview: PreviewProvider {
    static var previews: some View {
        WebView(url: "https://www.google.com")
    }
}

Thank you!

1
  • Welcome to Stack Overflow! Thanks for accepting! Commented Feb 24, 2020 at 7:55

2 Answers 2

6

Here's something that should do what you want. The WebView has a delegate in the Coordinator class. It changes a binding, to which the ContentView can react appropriately. Currently it's just a Text displaying the raw value of the state, but it can be replaced with an activity indicator of some sorts.

struct ContentView: View {
    @State var urlString = ""
    @State var workState = WebView.WorkState.initial

    var body: some View {
        VStack(spacing: 20) {
            WebView(urlString: self.$urlString, workState: self.$workState)

            Button("Play") {
                self.urlString = "https://www.example.com/"
            }
            Text("Current work = " + self.workState.rawValue)
        }
    }
}

struct WebView: UIViewRepresentable {
    enum WorkState: String {
        case initial
        case done
        case working
        case errorOccurred
    }

    @Binding var urlString: String
    @Binding var workState: WorkState

    func makeUIView(context: Context) -> WKWebView {
        let webView = WKWebView()
        webView.navigationDelegate = context.coordinator
        return webView
    }

    func updateUIView(_ uiView: WKWebView, context: Context) {
        switch self.workState {
        case .initial:
            if let url = URL(string: self.urlString) {
                uiView.load(URLRequest(url: url))
            }
        default:
            break
        }
    }

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

    class Coordinator: NSObject, WKNavigationDelegate {
        var parent: WebView

        func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
          self.parent.workState = .working
        }

        func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
            self.parent.workState = .errorOccurred
        }

        func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
            self.parent.workState = .done
        }

        init(_ parent: WebView) {
            self.parent = parent
        }
    }
}
Sign up to request clarification or add additional context in comments.

Comments

1

You will need to add an Coordinator to your UIViewRepresentable.

I think the answers for this question give you the right ideas.

SwiftUI WKWebView detect url changing

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.