Details
Solution
extension WKWebView {
var refreshControl: UIRefreshControl? { (scrollView.getAllSubviews() as [UIRefreshControl]).first }
enum PullToRefreshType {
case none
case embed
case custom(target: Any, selector: Selector)
}
func setPullToRefresh(type: PullToRefreshType) {
(scrollView.getAllSubviews() as [UIRefreshControl]).forEach { $0.removeFromSuperview() }
switch type {
case .none: break
case .embed: _setPullToRefresh(target: self, selector: #selector(webViewPullToRefreshHandler(source:)))
case .custom(let params): _setPullToRefresh(target: params.target, selector: params.selector)
}
}
private func _setPullToRefresh(target: Any, selector: Selector) {
let refreshControl = UIRefreshControl()
refreshControl.addTarget(target, action: selector, for: .valueChanged)
scrollView.addSubview(refreshControl)
}
@objc func webViewPullToRefreshHandler(source: UIRefreshControl) {
guard let url = self.url else { source.endRefreshing(); return }
load(URLRequest(url: url))
}
}
// https://stackoverflow.com/a/47282118/4488252
extension UIView {
class func getAllSubviews<T: UIView>(from parenView: UIView) -> [T] {
return parenView.subviews.flatMap { subView -> [T] in
var result = getAllSubviews(from: subView) as [T]
if let view = subView as? T { result.append(view) }
return result
}
}
func getAllSubviews<T: UIView>() -> [T] { return UIView.getAllSubviews(from: self) as [T] }
}
Usage
Setup
import UIKit
import WebKit
class ViewController2: UIViewController {
private weak var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
// ... create webView here
webView.navigationDelegate = self
}
}
// MARK: WKNavigationDelegate
extension ViewController2: WKNavigationDelegate {
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
webView.refreshControl?.endRefreshing()
}
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
webView.refreshControl?.endRefreshing()
}
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
webView.refreshControl?.endRefreshing()
}
}
Activate pull to refresh (option 1)
webView.setPullToRefresh(type: .embed)
Activate pull to refresh (option 2)
@objc func customPullToRefreshHandler(source: UIRefreshControl) {
guard let url = webView.url else { source.endRefreshing(); return }
webView.load(URLRequest(url: url))
}
// ....
webView.setPullToRefresh(type: .custom(target: self, selector: #selector(customPullToRefreshHandler(source:))))
Deactivate pull to refresh
webView.setPullToRefresh(type: .none)
Full sample
Do not forget to paste here the solution code
import UIKit
import WebKit
class ViewController: UIViewController {
private weak var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
createWebView()
webView.load("https://google.com")
// Way 1
webView.setPullToRefresh(type: .embed)
// Way 2
// webView.setPullToRefresh(type: .custom(target: self, selector: #selector(customPullToRefreshHandler(source:))))
}
private func createWebView() {
let webView = WKWebView(frame: .zero, configuration: .init())
view.addSubview(webView)
webView.navigationDelegate = self
self.webView = webView
webView.translatesAutoresizingMaskIntoConstraints = false
webView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
webView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
view.bottomAnchor.constraint(equalTo: webView.bottomAnchor).isActive = true
view.rightAnchor.constraint(equalTo: webView.rightAnchor).isActive = true
}
// @objc func customPullToRefreshHandler(source: UIRefreshControl) {
// guard let url = webView.url else { source.endRefreshing(); return }
// webView.load(URLRequest(url: url))
// print("WebView started loading")
// }
}
// MARK: WKNavigationDelegate
extension ViewController: WKNavigationDelegate {
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
webView.refreshControl?.endRefreshing()
}
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
webView.refreshControl?.endRefreshing()
}
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
webView.refreshControl?.endRefreshing()
}
}
extension WKWebView {
func load(_ urlString: String) {
guard let url = URL(string: urlString) else { return }
load(URLRequest(url: url))
}
}