Last updated on: May 27, 2023
In this tutorial, we are going to cover how to implement scroll to the top to your UITableView and UICollectionView easily.
Scroll to the top is a way to help the user to go at the top of the list fast without the need to scroll manually.
You can do that by making the pressing UINavigationBar‘s Title or with a button that pops up when we start to scroll down.
Contents
Add Scroll To Top in Navigation Bar Title for UITableView/UICollectionView
To make the title of UINavigationBar recognize our tap, we need to replace the already existed title, that UINavigationBar has, with a UILabel that recognizes tap gesture to scroll to the top when we are pressing it:
func TapLabelToScrollToTheTop(font: UIFont, textColor: UIColor, backgroundColor: UIColor) {
let titlelabel: UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 40))
titlelabel.text = self.navigationItem.title
titlelabel.textColor = textColor
titlelabel.font = font
titlelabel.backgroundColor = backgroundColor
titlelabel.textAlignment = .center
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.labelTapped))
tapGestureRecognizer.numberOfTapsRequired = 1
titlelabel.addGestureRecognizer(tapGestureRecognizer)
titlelabel.isUserInteractionEnabled = true
self.navigationItem.titleView = titlelabel
}
@objc func labelTapped(_ sender: UITapGestureRecognizer) { //Press the navigation label to go at the top
let topOffest = CGPoint(x: 0, y: -(self.tableView?.contentInset.top ?? 0))
self.tableView?.setContentOffset(topOffest, animated: true)
}
Code language: Swift (swift)
After that, we call the method in viewDidLoad() or viewWillAppear() and always after self.title
like this:
self.title = "Title"
TapLabelToScrollToTheTop(font: UIFont.systemFont(ofSize: 17, weight: .semibold), textColor: UIColor.white, backgroundColor: UIColor.clear)
Code language: Swift (swift)
Note: If the title doesn’t appear, use
self.navigationController?.navigationBar.topItem?.title = "Title"
instead ofself.title="Title"
Add Scroll To The Top in Button for UITableView/UICollectionView
This method is very common when you create a chat. The user scrolls to see their chat history and a button with an arrow appears to scroll back to the conversation.
First, we create the UIView and UIImageView, that contains the arrow, programmatically with the UITapGestureRecognizer and the auto layout constraints:
var arrowView = UIView(frame: CGRect.zero)
let arrowImgView = UIImageView(frame: CGRect.zero)
override func viewDidLoad() {
super.viewDidLoad()
//ArrowView
arrowView.layer.cornerRadius = 25
arrowView.backgroundColor = UIColor.black
arrowView.layer.borderWidth = 1.5
arrowView.layer.borderColor = UIColor.white.cgColor
self.view.addSubview(arrowView)
arrowImgView.image = UIImage(cgImage: UIImage(named: "back-arrow")!.cgImage!, scale: CGFloat(1.0), orientation: .right)
arrowImgView.image = arrowImgView.image!.withRenderingMode(.alwaysTemplate)
arrowImgView.tintColor = UIColor.white
let TapScrollDown = UITapGestureRecognizer(target: self, action: #selector(ScrollToTheTop(_:)))
arrowImgView.isUserInteractionEnabled = true
arrowImgView.addGestureRecognizer(TapScrollDown)
arrowView.addSubview(arrowImgView)
SetArrowAutoLayouts()
}
@objc func ScrollToTheTop(_ sender: UITapGestureRecognizer) {
let topOffest = CGPoint(x: 0, y: -(self.tableView?.contentInset.top))
self.tableView.setContentOffset(topOffest, animated: true)
}
@objc func SetArrowAutoLayouts() {
arrowView.translatesAutoresizingMaskIntoConstraints = false
arrowViewWidth = arrowView.widthAnchor.constraint(equalToConstant: 50)
arrowViewHeight = arrowView.heightAnchor.constraint(equalToConstant: 50)
arrowViewBottom = arrowView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: -50)
arrowViewRight = arrowView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: 55)
arrowViewWidth.isActive = true
arrowViewHeight.isActive = true
arrowViewBottom.isActive = true
arrowViewRight.isActive = true
arrowImgView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
arrowImgView.topAnchor.constraint(equalTo: arrowView.topAnchor, constant: 8),
arrowImgView.leadingAnchor.constraint(equalTo: arrowView.leadingAnchor, constant: 8),
arrowImgView.bottomAnchor.constraint(equalTo: arrowView.bottomAnchor, constant: -8),
arrowImgView.trailingAnchor.constraint(equalTo: arrowView.trailingAnchor, constant: -8)
])
}
Code language: Swift (swift)
Next, we’re going to add to our UITableView/UICollectionView the scrollViewDidScroll method.
This method detects the X and Y position of the UIScrollView that UITableView/UICollectionView has. We’re gonna use this to detect when the user starts to scrolls down:
var scrollTop = true
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let offsetY = scrollView.contentOffset.y
if offsetY > 400 {
if scrollTop {
arrowViewRight.constant = -12
UIView.animate(withDuration: 0.3) { self.view.layoutIfNeeded() }
scrollTop = false
}
}else{
if !scrollTop {
arrowViewRight.constant = 55
UIView.animate(withDuration: 0.3) { self.view.layoutIfNeeded() }
scrollTop = true
}
}
}
Code language: Swift (swift)
If you want to show the button as soon as the user scrolls down, change the value from 400 to something smaller. The smaller the value, the sooner the Scroll To Top arrow will appear.
And that’s it! Done!
You can find the final project here
If you have any questions, please feel free to leave a comment below