Indexed Table View iOS Tutorial

An indexed table is fundamentally the same as a plain-style table, but with an index running down the right hand edge. Typically, this index displays letters or numbers, which the user can tap to automatically scroll the table to the relevant section. In this tutorial,a number of car brands will be displayed in a table view and the first letter will be used for the index. This tutorial is made with Xcode 9 and built for iOS 11.

Open Xcode and create a new Single View App.

For product name, use IOS11IndexedTableViewTutorial and then fill out the Organization Name and Organization Identifier with your customary values. Enter Swift as Language and choose Next.

Go to the storyboard. Remove the View Controller from the Storyboard and drag a Navigation Controller to the Scene. This will also add the Table View Controller. Select the Navigation Controller and go to The Attribute inspector. In the View Controller section check the "Is Initial View Controller" checkbox.

Select the Table View Cell and go to the Attributes Inspector. In the Table View Cell section set the Identifier  to "Cell".

The storyboard will look like this.

Since the View Controller is removed from the Storyboard the ViewController.swift file can also be deleted from the project. Add a new file to the project, select iOS->Source->Cocoa Touch Class. Name it TableViewController and make it a subclass of UITableViewController.

add-file-table-view-controller

The TableViewController class needs to be linked to The Table View Controller object in the Storyboard. Select it and go the Identity Inspector. In the Custom Class section change the class to TableViewController.

Go to TableViewController.swift and create the following properties

var carsDictionary = [String: [String]]()
var carSectionTitles = [String]()
var cars = [String]()

In the ViewDidLoad method fill the cars arrays with some data. Change viewDidLoad in

override func viewDidLoad() {
    super.viewDidLoad()
    
    cars = ["Audi", "Aston Martin","BMW", "Bugatti", "Bentley","Chevrolet", "Cadillac","Dodge","Ferrari", "Ford","Honda","Jaguar","Lamborghini","Mercedes", "Mazda","Nissan","Porsche","Rolls Royce","Toyota","Volkswagen"]
    
    // 1
    for car in cars {
        let carKey = String(car.prefix(1))
            if var carValues = carsDictionary[carKey] {
                carValues.append(car)
                carsDictionary[carKey] = carValues
            } else {
                carsDictionary[carKey] = [car]
            }
    }
    
    // 2
    carSectionTitles = [String](carsDictionary.keys)
    carSectionTitles = carSectionTitles.sorted(by: { $0 < $1 })
}
  1. The first letter is extracted from each car and is used as a key of the carsDictionary. With this key a new array of cars is created, or when the key exists the car item is appended to the array.
  2. The keys of the carsDictionary are sorted by alphabetical order.

Next, change the delegate methods of the TableViewController 

override func numberOfSections(in tableView: UITableView) -> Int {
    // 1
    return carSectionTitles.count
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // 2
    let carKey = carSectionTitles[section]
    if let carValues = carsDictionary[carKey] {
        return carValues.count
    }
        
    return 0
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    // 3
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
      
    // Configure the cell...
    let carKey = carSectionTitles[indexPath.section]
    if let carValues = carsDictionary[carKey] {
        cell.textLabel?.text = carValues[indexPath.row]
    }

    return cell
}
  1. The number of items in the carSectionTitles array will be returned in the numberOfSections(in:) method.
  2. The number of rows based on the number of cars in each section index is returned.
  3. For each section index the car name is assigned to the text property of the textLabel property of the current cell.

To display a header title in each section, implement the tableview(_:titleForHeaderInSection:) method.

override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    return carSectionTitles[section]
}

To add an indexed table view, implement the sectionIndexTitles(for:) method.

 override func sectionIndexTitles(for tableView: UITableView) -> [String]? {
    return carSectionTitles
}

Build and Run the project, select an index and you should see the table view moving to the correct row.

You can download the source code of the IOS11IndexedTableViewTutorial at the ioscreator repository on Github