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
Setting Scroll Position in Uitableview
Uidevice Currentdevice Model Possible Values
Referring to Weak Self Inside a Nested Block
How to Display an Image Using Url
How to Add Iphonex Launch Image
Broken Uisearchbar Animation Embedded in Navigationitem
"Your Binary Is Not Optimized for iPhone 5" (Itms-90096) When Submitting
How to Split Filename from File Extension in Swift
How to Localize the Images in Images.Xcassets
How to Write an Objective-C Completion Block
Ios11 Photo Library Access Is Possible Even If Settings Are Set to "Never"
Downloading Uiimage via Alamofireimage
How to Load a Url Link That Is Inside a Web View and Keep It in That Web View in Swift
Getting Back a Date from a String
How to Change the Color of the Text in a Uipickerview Under iOS 7