Pull-to-refresh has become a common user interface paradigm in the mobile space. It made its introduction several years ago in Tweetie, a very popular Twitter client created by Loren Brichter.
The idea is simple. The user pulls down to refresh the contents of a table or collection view. Since the addition of the UIRefreshControl
class in iOS 6, pull-to-refresh has become very easy to add to table views, collection views, and even scroll views.
Jump Start
To speed things up, I created an Xcode project that fetches weather data from the Dark Sky API and displays the weather data for the coming days in a table view. Clone or download the project from GitHub if you want to follow along. Take a moment to browse the project.
When the user pulls the table view down, the application should send another fetch request to the Dark Sky API, show a refresh control, and update the table view when the fetch request is completed. Let's start by adding a refresh control to the table view.
Adding a Refresh Control
Open the project and select ViewController.swift in the Project Navigator on the right. In this view controller, the weather data is fetched from the Dark Sky API and displayed in a table view.
The first thing we need to do is create an instance of the UIRefreshControl
class. Declare a private constant property at the top and assign an instance of the UIRefreshControl
class to it.
private let refreshControl = UIRefreshControl()
The refresh control is not part of the view hierarchy yet. We need to add it to the table view. Navigate to the setupTableView()
method of the ViewController
class and add the following snippet to add the refresh control to the table view of the view controller.
// Add Refresh Control to Table View
if #available(iOS 10.0, *) {
tableView.refreshControl = refreshControl
} else {
tableView.addSubview(refreshControl)
}
It may look a bit more complex than you expected. The reason is simple. Since iOS 10, the UITableView
and UICollectionView
classes have a refreshControl
property. You can add a refresh control to a table or collection view by assigning an instance of the UIRefreshControl
class to this property.
If your application targets versions prior to iOS 10, you simply add the refresh control as a subview to the table view. The table view takes care of the rest. It knows what to do when a UIRefreshControl
instance is added as a subview.
Adding a Target and Action
We're not done yet. The UIRefreshControl
is a UIControl
subclass. To make it work, we need to add a target and an action for the valueChanged
event. This is easy and something you're probably already familiar with.
// Configure Refresh Control
refreshControl.addTarget(self, action: #selector(refreshWeatherData(_:)), for: .valueChanged)
We add the view controller as a target for the refreshWeatherData(_:)
action. The action is triggered when the valueChanged
event occurs, that is, when the user pulls and releases the table view.
The implementation of refreshWeatherData(_:)
is straightforward. The view controller fetches new weather data from the Dark Sky API by invoking fetchWeatherData()
.
@objc private func refreshWeatherData(_ sender: Any) {
// Fetch Weather Data
fetchWeatherData()
}
Updating the User Interface
In fetchWeatherData()
, we update the user interface by invoking updateView()
. But we also need to tell the refresh control that the fetch request completed and that it can stop refreshing. We do this by invoking endRefreshing()
on the refresh control.
private func fetchWeatherData() {
dataManager.weatherDataForLocation(latitude: 37.8267, longitude: -122.423) { (location, error) in
DispatchQueue.main.async {
if let location = location {
self.days = location.days
}
self.updateView()
self.refreshControl.endRefreshing()
self.activityIndicatorView.stopAnimating()
}
}
}
Customizing the Refresh Control
It's possible to customize a UIRefreshControl
instance to some extent. You can, for example, set the tint color of the refresh control.
refreshControl.tintColor = UIColor(red:0.25, green:0.72, blue:0.85, alpha:1.0)
You can also show a message to the user by setting the attributedTitle
property of the refresh control.
refreshControl.attributedTitle = NSAttributedString(string: "Fetching Weather Data ...", attributes: attributes)
But that's about all the customization you can do to a refresh control. While UIRefreshControl
is a convenient class and very easy to use, it's limited in terms of customizability.