Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
SwiftUI Webview with a Progress Bar
struct Webview: UIViewControllerRepresentable {
let url: URL
func makeUIViewController(context: Context) -> WebviewController {
let webviewController = WebviewController()
let request = URLRequest(url: self.url, cachePolicy: .returnCacheDataElseLoad)
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)
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)
}
}
}
@OOXXXX
Copy link

OOXXXX commented May 22, 2020

Hi, your code is wonderful, but I have some problems when setting the constraints of the web view. Because on iPad, the web view will be scaled. Could you help me to solve the problem? Thanks
CleanShot 2020-0522 -0921@2x

@stevencolvin
Copy link

stevencolvin commented Nov 24, 2020

I am also having a problem with constraints, particularly with the bottom restraint. Part of the bottom of the webpage is blocked off, and I am unable to click anything on the bottom portion of the webpage.

@marc-lallias
Copy link

marc-lallias commented Dec 2, 2020

https://medium.com/macoclock/how-to-use-webkit-webview-in-swiftui-4b944d04190a

Use this one if you want better constraint management

@joshbetz
Copy link
Author

joshbetz commented Dec 4, 2020

Updated this with better constraint management, although that example looks nicer in general.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment