TEAM LICENSES: Save money and learn new skills through a Hacking with Swift+ team license >>

SOLVED: Refresh and Go back function for Webkit's Webview in SwiftUI

Forums > SwiftUI

Hi again!

Please, I will like to ask if it is possible to have webkit's webview refresh an embedded webpage in SwiftUI, perhaps when the user pulls the page down. And is it possible to add a back function, to return to whatever previous page apart from the main "homepage"?

This is my Webview code:

import SwiftUI
import WebKit

struct WebView: UIViewRepresentable {
    typealias UIViewType = WKWebView

    let webView: WKWebView

    func makeUIView(context: Context) -> WKWebView {
        return webView
    }

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

struct Webview: UIViewControllerRepresentable {
    let url: URL
    func makeUIViewController(context: Context) -> WebviewController {
        let webviewController = WebviewController()
        let request = URLRequest(url: self.url, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData)
        webviewController.webview.load(request)
        return webviewController
    }
    func updateUIViewController(_ webviewController: WebviewController, context: Context) {
        //

    }
}

class WebviewController: UIViewController, WKNavigationDelegate {
    lazy var webview: WKWebView = WKWebView()
    lazy var progressbar: UIProgressView = UIProgressView()
    deinit {
        self.webview.removeObserver(self, forKeyPath: "estimatedProgress")
        self.webview.scrollView.removeObserver(self, forKeyPath: "contentOffset")
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        self.webview.navigationDelegate = self
        self.view.addSubview(self.webview)
        self.webview.frame = self.view.frame
        self.webview.translatesAutoresizingMaskIntoConstraints = false
        self.view.addConstraints([
            self.webview.topAnchor.constraint(equalTo: self.view.topAnchor),
            self.webview.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
            self.webview.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
            self.webview.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
        ])
        self.webview.addSubview(self.progressbar)
        self.setProgressBarPosition()
        webview.scrollView.addObserver(self, forKeyPath: "contentOffset", options: .new, context: nil)
        webview.allowsLinkPreview = true
        self.progressbar.progress = 0.1
        webview.addObserver(self, forKeyPath: "estimatedProgress", options: .new, context: nil)
    }
    func setProgressBarPosition() {
        self.progressbar.translatesAutoresizingMaskIntoConstraints = false
        self.webview.removeConstraints(self.webview.constraints)
        self.webview.addConstraints([
            self.progressbar.topAnchor.constraint(equalTo: self.webview.topAnchor, constant: self.webview.scrollView.contentOffset.y * -1),
            self.progressbar.leadingAnchor.constraint(equalTo: self.webview.leadingAnchor),
            self.progressbar.trailingAnchor.constraint(equalTo: self.webview.trailingAnchor),
        ])
    }
    // MARK: - Web view progress
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        switch keyPath {
        case "estimatedProgress":
            if self.webview.estimatedProgress >= 1.0 {
                UIView.animate(withDuration: 0.3, animations: { () in
                    self.progressbar.alpha = 0.0
                }, completion: { finished in
                    self.progressbar.setProgress(0.0, animated: false)
                })
            } else {
                self.progressbar.isHidden = false
                self.progressbar.alpha = 1.0
                progressbar.setProgress(Float(self.webview.estimatedProgress), animated: true)
            }
        case "contentOffset":
            self.setProgressBarPosition()
        default:
            super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
        }
    }
}

Many thanks. :)

1      

Maybe it's not a solution with YOUR code but a very good option/replacement. Instead of WKWebView to use SafariServices like so. And have all those options by default instead having real pain by passing values with WKWebView )))

import SwiftUI
import SafariServices

struct SafariBrowserView: View {
    @State private var searchURL: URL = URL(string: "https://google.com")!

    var body: some View {
        SafariBrowser(searchURL: $searchURL)
    }
}

#Preview {
    SafariBrowserView()
}

struct SafariBrowser: UIViewControllerRepresentable {
    @Binding var searchURL: URL

    func makeUIViewController(context: Context) -> SFSafariViewController {
        let browser = SFSafariViewController(url: searchURL)
        return browser
    }

    func updateUIViewController(_ uiViewController: SFSafariViewController, context: Context) {
        //
    }
}

1      

Hacking with Swift is sponsored by String Catalog.

SPONSORED Get accurate app localizations in minutes using AI. Choose your languages & receive translations for 40+ markets!

Localize My App

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.