Reputation: 33
I'm very new to developing. I'm building a WebView and I want it to have pull to refresh capabilities. How do I go about doing that in swift?
My code in the View Controller is
@IBOutlet var webView: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
func webViewDidFinishLoad(webView: UIWebView) {
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
}
func webViewDidStartLoad(webView: UIWebView) {
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
}
let url = NSURL (string: "https://www.foo.com");
let requestObj = NSURLRequest(URL: url!);
webView.loadRequest(requestObj);
NSUserDefaults.standardUserDefaults().registerDefaults(["UserAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/601.5.17 (KHTML, like Gecko) Version/9.1 Safari/601.5.17"])
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
Upvotes: 3
Views: 10122
Reputation: 25294
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] }
}
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)
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))
}
}
Upvotes: 4
Reputation: 690
You can use this one
Write this in DidLoad method
webViewHome.scrollView.delegate = self;
And then write this method
#pragma mark Scrollview delegate
Note: Please make sure you didn't set scrollview bounces property to No otherwise this method will not call
Upvotes: 1
Reputation: 89
Following code will put the refresh control in scrollview of webview.Initially it will load google.com. To see pull to refresh clearly I have set white color to the background of scroll view so it is clearly visible and on pull to refresh webview opens facebook page.
class ViewController: UIViewController,UIWebViewDelegate {
@IBOutlet weak var webView: UIWebView!
var refreshControl:UIRefreshControl?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.refreshControl = UIRefreshControl.init()
refreshControl!.addTarget(self, action:#selector(refreshControlClicked), for: UIControlEvents.valueChanged)
self.webView.scrollView.addSubview(self.refreshControl!)
self.webView.scrollView.backgroundColor = UIColor.white
self.webView.delegate = self
let url:URL = URL.init(string:"https://www.google.com")!
self.loadRequestWithUrl(URLRequest.init(url: url))
}
func webViewDidStartLoad(_ webView: UIWebView) {
NSLog("website loaded")
}
func loadRequestWithUrl(_ urlRequest : URLRequest?){
if(urlRequest != nil){
self.webView.loadRequest(urlRequest!)
}
}
func refreshControlClicked(){
let url:URL = URL.init(string:"https://www.facebook.com")!
self.loadRequestWithUrl(URLRequest.init(url: url))
}
}
Upvotes: 1
Reputation: 49710
Your code is buggy you added two Web view Delegate in side the ViewDidLoad
method that must be following and check the following viewDidLoad
code for adding Pull to Refresh in web view:
@IBOutlet var webView: UIWebView!
var refController:UIRefreshControl = UIRefreshControl()
override func viewDidLoad() {
super.viewDidLoad()
let url = NSURL (string: "https://www.foo.com");
let requestObj = NSURLRequest(URL: url!);
webView.loadRequest(requestObj);
NSUserDefaults.standardUserDefaults().registerDefaults(["UserAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/601.5.17 (KHTML, like Gecko) Version/9.1 Safari/601.5.17"])
refController.bounds = CGRectMake(0, 50, refController.bounds.size.width, refController.bounds.size.height)
refController.addTarget(self, action: Selector("mymethodforref:"), forControlEvents: UIControlEvents.ValueChanged)
refController.attributedTitle = NSAttributedString(string: "Pull to refresh")
webView.scrollView.addSubview(refController)
}
func mymethodforref(refresh:UIRefreshControl){
webView.reload()
refController.endRefreshing()
}
func webViewDidFinishLoad(webView: UIWebView) {
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
}
func webViewDidStartLoad(webView: UIWebView) {
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Upvotes: 5