Pull to Refresh
Pull-to-refresh is a UI effect that you’ll use over and over. I’ll walk you through the simplest implementation where the scrolling distance controls the alpha
and rotation
of the refresh icon.
Setup
You can download my project on GitHub.
To begin you’ll need a UITableView
with some dummy cells. Add a UIImageView
for the loading icon on top of the UITableView
. Set the alpha
in InterfaceBuilder to 0
.
Assets
Then in assets.xcassets
add a series of images for the loading spinner. I found a gif online and split it into its component images and then added them inside assets.xcassets
. The more images you use the smoother the animation will look. Name them with a similarly uniform naming pattern because we will need to load them as UIImage
programatically.
UIScrollViewDelegate
UITableView
is a subclass of… that’s right, UIScrollView
. To access the ContentOffset
(the amount the user has scrolled) implement UIScrollViewDelegate
and add this delegate method to the ViewController
.
Here is where the magic happens. The three constants allow you to customize the animation. The alpha
and rotation
are based on the scrollView.contentOffset.y
.
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.contentOffset.y <= 0 {
// 0.0 - 1.0: larger numbers delay how far down the pull needs to be before the spinner appears.
let loadingAppearanceOffset: CGFloat = 0.2
// 1 - 5: larger numbers slow down the rotation speed of the spinner.
let loadingAppearanceSpeed: CGFloat = 3
// Set with the number of images in assets.xcassets. More images will make for a smoother animation.
let loadingNumberOfImages: Int = 20
let alpha: CGFloat = (abs(scrollView.contentOffset.y) / 100) - loadingAppearanceOffset
let imageNumber = Int(abs(scrollView.contentOffset.y) / loadingAppearanceSpeed) % loadingNumberOfImages
let imageName = "loading" + String(imageNumber)
let image = UIImage(named: imageName)
loadingImageView.alpha = min(alpha, 1.0)
loadingImageView.image = image
loadingImageView.tintColor = UIColor.init(hexString: "C9CBDE")
}
}
Networking
You’ll also need to implement scrollViewDidEndDragging
to know when to make your API calls. I’ve hardcoded -20
as a minimum amount of down-pull required to activate pull-to-refresh. You can customize this as you like.
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if scrollView.contentOffset.y <= -20 {
// A pull to refresh occured. Make your network calls.
}
}