How to Use Pull to Refresh in Swift

How to use pull to refresh in Swift?

Pull to refresh is built in iOS. You could do this in swift like

let refreshControl = UIRefreshControl()

override func viewDidLoad() {
super.viewDidLoad()

refreshControl.attributedTitle = NSAttributedString(string: "Pull to refresh")
refreshControl.addTarget(self, action: #selector(self.refresh(_:)), for: .valueChanged)
tableView.addSubview(refreshControl) // not required when using UITableViewController
}

@objc func refresh(_ sender: AnyObject) {
// Code to refresh table view
}

At some point you could end refreshing.

refreshControl.endRefreshing()

Fix iOS pull to refresh animation

Adding refresh control as a subview could be a problem. UITableView now have property for the refresh control. Here you have description from apple documentation how you should implement that:
https://developer.apple.com/documentation/uikit/uirefreshcontrol

How to pull to refresh without tableView?

There doesn't appear to be anything wrong with your approach.

Here is a complete example -- it adds a "full view" scrollView, with a 200-pt tall red subview (so we can see the effect).

When you drag down, you should see the UIRefreshControl "spinner" appear. Drag down far enough, and it will call the updateView() func. Since we don't have your SyncScheduler code, I added a 2-second async delay to simulate the process:

final class CategoryBreakdownViewController: UIViewController {

private let scrollView = UIScrollView()
var refreshControl = UIRefreshControl()

override func viewDidLoad() {
super.viewDidLoad()

scrollView.backgroundColor = .systemTeal
scrollView.translatesAutoresizingMaskIntoConstraints = false

let testView = UIView()
testView.backgroundColor = .red
testView.translatesAutoresizingMaskIntoConstraints = false

scrollView.addSubview(testView)
view.addSubview(scrollView)

let contentGuide = scrollView.contentLayoutGuide
let frameGuide = scrollView.frameLayoutGuide

NSLayoutConstraint.activate([
scrollView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),

testView.topAnchor.constraint(equalTo: contentGuide.topAnchor, constant: 20.0),
testView.leadingAnchor.constraint(equalTo: contentGuide.leadingAnchor, constant: 20.0),
testView.trailingAnchor.constraint(equalTo: contentGuide.trailingAnchor, constant: -20.0),
testView.bottomAnchor.constraint(equalTo: contentGuide.bottomAnchor, constant: -20.0),

testView.widthAnchor.constraint(equalTo: frameGuide.widthAnchor, constant: -40.0),
testView.heightAnchor.constraint(equalToConstant: 200.0),
])

setupRefreshControl()
}

private func setupRefreshControl() {
scrollView.alwaysBounceVertical = true
scrollView.bounces = true
refreshControl.addTarget(self, action: #selector(updateView), for: .valueChanged)
self.scrollView.addSubview(refreshControl)
}

@objc func updateView() {

// simulate a background process that takes 2 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0, execute: {
self.refreshControl.endRefreshing()
})

// SyncScheduler.syncImmediately(
// success: {
// self.refreshControl.endRefreshing()
// },
// failure: { [weak self] errorMessage in
// self?.present(message: errorMessage, style: .error)
// self?.refreshControl.endRefreshing()
// }
// )

}
}

Pull to refresh default refresh level change

Since I do not think you can change the behaviour of how much distance you have to travel to initiate the refresh I would just trigger it manually when user scrolled enough, something like:

func scrollViewDidScroll(_ scrollView: UIScrollView) {
guard !refreshControl.isRefreshing else {
return//do nothing if we are already refreshing
}

//set your threshold to whatever feels ok (I used -30 here)
if scrollView.contentOffset.y < -30 {
refreshTable()
refreshControl.beginRefreshing()
}
}

You also might have to play a bit with offsetting table view properly when refresh is active so that the UIActivityIndicator is above your cells, and then adjust it again when you finish refreshing. Note you will have to call refreshControl.endRefreshing() in refreshTable() method once API calls are completed or whatever you are doing there...

Pull to refresh in Swift

I gather your class inherits UITableViewController. UITableViewController already declares the refreshControl property like this:

@availability(iOS, introduced=6.0)
var refreshControl: UIRefreshControl?

You don't need to override it. Just get rid of your var declaration and assign to the inherited property.

Since the inherited property is Optional, you need to use a ? or ! to unwrap it:

refreshControl = UIRefreshControl()
refreshControl!.attributedTitle = NSAttributedString(string: "Pull to refresh")
refreshControl!.addTarget(self, action: "refresh:", forControlEvents: UIControlEvents.ValueChanged)
tableView.addSubview(refreshControl!)

Pull to refresh for WKWebView

Looks like your refreshWebViewClass should be a Coordinator. Then, in your addTarget, the target would be context.coordinator, not self, which doesn't make sense here, since self doesn't actually implement this method.



Related Topics



Leave a reply



Submit