December 11, 2019

UITableView scroll to top with Swift

UITableView scroll to top with Swift

Scrolling to the top of a UITableView can be a useful feature depending on the type of app that you are making. If you have a tableview with hundreds of cells it can be annoying scrolling to the top of the tableview once you have scrolled far down the tableview.

In this tutorial we will create a very basic UITableView and when we tap on a cell it will scroll to the top of the UITableView.

Step 1: Create the UITableView

I have started with a new project for this tutorial, if you have a tableview setup you can skip to step 3.

Let's add a tableview to our view controller and then connect it to an IBOutlet.

Now we need to add our constraints. I am going to set the top, right, bottom and left constraints to be 0.

Step 2: Setup tableview

Setting up a tableview is very simple. To start with we will need to add a new variable which will be an array of integers and it will be used as the datasource to the tableview. We will also need to conform to the UITableViewDelegate and UITableViewDataSource protocols.

Let's start with our datasource. To do this we need to add the following variable to our ViewController:

var tableViewDataSource = Array(0...100)

This will create an array with the values of 0 to 100.

Let's make sure that our ViewController inherits from the UITableViewDelegate and UITableViewDataSource protocols. To do that, update your ViewController class to look like the following:

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource

If you build and run this it will break because we have not implemented the two required methods of UITableViewDataSource.

Ok, now that we are inheriting from those two UITableView protocols, we need to implement the required methods, let's do that now. Add the following methods to your ViewController, I have added it below my viewDidLoad method:

func tableView(_ tableView: UITableView, 
               numberOfRowsInSection section: Int) -> Int {
    return self.tableViewDataSource.count
}
    
func tableView(_ tableView: UITableView, 
               cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = UITableViewCell()
    cell.textLabel?.text = "\(self.tableViewDataSource[indexPath.row])"
    return cell
}

The first method, numberOfRowsInSection, we can implement because we have our tableViewDataSource that we created earlier.

The second method, cellForRowAt, returns a cell. To get the text for this cell we use indexPath.row to get the corresponding element in the tableViewDataSource, and we assign that element's value to the cell's textLabel.

The last thing that we need to do is to set the tableview's delegate and datasource. To do this add the following two lines to your viewDidLoad method:

self.tableView.delegate = self
self.tableView.dataSource = self

If you build and run the app now you should see the following:

Step 3: Get the tableview to scroll the top

Getting the tableview to scroll is extremely simple, to get the tableview to scroll to the top add the following method, scrollToTop, to your ViewController:

private func scrollToTop() {
    // 1
    let topRow = IndexPath(row: 0,
                           section: 0)
                           
    // 2
    self.tableView.scrollToRow(at: topRow,
                               at: .top,
                               animated: true)
}
  1. To scroll to the top of our tableview we need to create a new IndexPath. This index path has two arguments, row and section. All we want to do is scroll to the top of the table view, therefore we pass 0 for the row argument and 0 for the section argument.
  2. UITableView has the scrollToRow method built in. It takes 3 arguments. The first one will be the IndexPath that we created, the second will be where you want the table to to stop, this can be top, bottom, middle or none. If you select top like we have, it will put position the cell at the index path that we have passed through, right at the top of the table view when it scrolls to it. If you select middle, it will position the cell in the middle of the tableview when it scrolls to it, and bottom will position the cell at the bottom of the tableview when it scrolls to it, I will add screenshots below to show this difference. Lastly we tell it to animate when it scrolls.

In the screenshots below I have changed the row of my index path to be 20 instead of 0. If it is kept at 0 using top, bottom, middle or none will make no difference and it will always scroll to the top. (Please note that if you build and run you will not be able to scroll just yet, we still need to call this method which we will do after the screenshots.)

This is my starting point before I have it scroll:

Using .top:

Using .middle:

Using .bottom:

Ok, now that we have all of that done, let's call this method so that we can get the scrolling to work.

To do that we need to implement a UITableViewDelegate method. We have inherited from the UITableViewDelegate but we have not used any methods from it yet, so let's do that now.

Add the following code below the cellForRowAt method:

func tableView(_ tableView: UITableView, 
               didSelectRowAt indexPath: IndexPath) {
    self.scrollToTop()
}

If you build and run this code it should function like the below:

The complete ViewController code:

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    @IBOutlet weak var tableView: UITableView!
    var tableViewDataSource = Array(0...100)
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.tableView.delegate = self
        self.tableView.dataSource = self
    }
    
    func tableView(_ tableView: UITableView, 
                   numberOfRowsInSection section: Int) -> Int {
        return self.tableViewDataSource.count
    }
    
    func tableView(_ tableView: UITableView, 
                   cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell()
        cell.textLabel?.text = "\(self.tableViewDataSource[indexPath.row])"
        return cell
    }
    
    func tableView(_ tableView: UITableView, 
                   didSelectRowAt indexPath: IndexPath) {
        self.scrollToTop()
    }
    
    private func scrollToTop() {
        let topRow = IndexPath(row: 0,
                               section: 0)
        self.tableView.scrollToRow(at: topRow,
                                   at: .top,
                                   animated: true)
    }
}

The full project can be found here.