Using Collection Views in iOS

Introduction

Table views are great for displaying large amounts of data in rows that the user can scroll through. While table views are perfect for the smaller, narrower screen of the iPhone, they are limited to scrolling rows of data up and down. If you want to scroll data horizontally or display multiple columns of data, you can use a Collection View instead.

Like table views, Collection Views need a data source and a delegate that implements methods that define how much data will appear in the Collection View. Think of Collection Views as more versatile table views.

Collection Views display data in cells that make up a grid that can scroll vertically or horizontally. To see how to create a simple Collection View, follow these steps:

  1. Click the Main.storyboard file in the Navigator pane. Xcode displays the single view.
  2. Click the Library icon to open the Object Library window.
  3. Drag and drop a Collection View.
  4. Resize the Collection View so it fills the entire screen.
  5. Choose Editor > Resolve Auto Layout Issues > Reset to Suggested Constraints. Xcode adds constraints to the Collection View.
  6. Click Collection View Cell in the Document Outline.
  7. Choose View > Inspectors > Show Attributes Inspector, or click the Attributes Inspector icon in the upper right corner of the Xcode window.
  8. Click in the Identifier text field, type customCell, and press ENTER.
  9. Choose View > Assistant Editor > Show Assistant Editor, or click the Assistant Editor icon in the upper right corner of the Xcode window.
  10. Move the mouse pointer over the Collection View, hold down the Control key, and Ctrl-drag under the class ViewController line in the ViewController.swift file.
  11. Release the Control key and the left mouse button. A popup window appears.
  12. Click in the Name text field, type collectionView, and click the Connect button. Xcode creates an IBOutlet as follows:
@IBOutlet var collectionView: UICollectionView!
  1. Choose View > Standard Editor > Show Standard Editor, or click the Standard Editor icon in the upper right corner of the Xcode window.
  2. Click the ViewController.swift file in the Navigator pane.
  3. Modify the class ViewController line by adding UICollectionViewDataSource, UICollectionViewDelegate as follows:
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {

The purpose of this code is to identify the ViewController.swift file as both the delegate and data source for the Collection View.

Underneath the class ViewController line, add the following:

var cellColor = true

Modify the viewDidLoad method as follows:

override func viewDidLoad() {
    super.viewDidLoad()
    collectionView.dataSource = self 
    collectionView.delegate = self
}

Add the following function underneath the viewDidLoad method to define how many items appear in the Collection View section. By default, a Collection View has one section:

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return 100 
}

Add the following function underneath the viewDidLoad method to fill the Collection View Cells with data:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) 
-> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "customCell", for: indexPath)
    if cellColor {
        cell.backgroundColor = UIColor.yellow
    } else {
        cell.backgroundColor = UIColor.green
    }
    cellColor = !cellColor
    return cell 
}

Displaying Data in a Collection View

The main purpose of a Collection View is to display information in cells. To display information in a cell takes several steps:

  • Drag and drop objects onto the Collection View Cell.
  • Create a new .swift class file to represent the Collection View Cell.
  • Connect this new .swift class file to the Collection View Cell in the Identity Inspector pane.
  • Ctrl-drag from the objects on the Collection View Cell to the .swift class file to create IBOutlet variables to represent each object.
  • Write code in the cellForItemAt function to store data in each Collection View Cell.

When designing a Collection View Cell, you can resize its height and width. In addition, you can also define the spacing between cells along with how much space cells appear away from the top, left, bottom, or right edges of the screen.

To see how to display text in a Collection View Cell, follow these steps:

  1. Click the Main.storyboard file in the Navigator pane. Xcode displays the single view.
  2. Click the Library icon to open the Object Library window.
  3. Drag and drop a Collection View anywhere on the view.
  4. Resize the Collection View so it fills the entire screen.
  5. Choose Editor > Resolve Auto Layout Issues > Reset to Suggested Constraints. Xcode adds constraints to the Collection View.
  6. Choose File > New > File. Xcode displays a list of templates.
  7. Choose Cocoa Touch Class under the iOS category and click the Next button. Another dialog appears, asking for a class name and subclass.
  8. Click in the Class text field and type ItemCell.
  9. Click in the Subclass of popup menu and choose UICollectionViewCell.
  10. Click the Next button. Xcode asks where to store the file.
  11. Click the Create button. Xcode displays the itemCell.swift file in the Navigator pane.
  12. Click the Main.storyboard in the Navigator pane, click the Collection View Cell in the Document Outline and choose View > Inspectors > Show Attributes Inspector, or click the Attributes Inspector icon in the upper right corner of the Xcode window.
  13. Click in the identifier text field, type customCell, and press ENTER
  14. Click in the Background color popup menu and choose a color such as yellow. Xcode highlights the Collection View Cell.
  15. Choose View > Inspectors > Show Identity Inspector, or click the Identity Inspector icon in the upper right corner of the Xcode window.
  16. Click in the Class popup menu and choose itemCell.
  17. Click the Library icon to open the Object Library window and drag and drop a label in the center of the Collection View Cell.
  18. Click the Align icon at the bottom of the Xcode window and select the Horizontally in Container and Vertically in Container check boxes. Then click the Add 2 Constraints button. Xcode adds constraints to make sure the label is centered inside the Collection View Cell.
  19. Click Collection View in the Document Outline and then choose View > Inspectors > Show Size Inspector, or click the Size Inspector icon in the upper right corner of the Xcode window.
  20. Click in the Cell Size Width text fields, type 100, and press ENTER.
  21. Click in the Cell Size Height text fields, type 100, and press ENTER.
  22. Click in the Min Spacing For Cells text field, type 20, and press ENTER.
  23. Click in the Section Insets Top text field, type 15, and press ENTER. Xcode moves the Collection View Cell down from the top.
  24. Click in the Section Insets Left text field, type 15, and press ENTER. Xcode moves the Collection View Cell away from the left edge.
  25. Choose View > Assistant Editor > Show Assistant Editor, or click the Assistant Editor icon in the upper right corner of the Xcode window. This displays the Main.storyboard file on the left and the ViewController.swift file on the right.
  26. Move the mouse pointer over the Collection View in the Document Outline, hold down the Control key, and Ctrl-drag from the Collection View to the ViewController.swift file underneath the class ViewController line.
  27. Release the Control key and the left mouse button. A popup window appears.
  28. Click in the Name text field and type collectionView. Then click the Connect button. Xcode creates an IBOutlet as follows:
@IBOutlet var collectionView: UICollectionView!
  1. Move the mouse pointer over Label under customCell in the Document Outline. If Xcode does not display the itemCell.swift file in the Assistant Editor, click the two intertwined circles icon at the top of the Assistant Editor to display a menu.
  2. Choose Automatic > itemCell.swift
  3. Move the mouse pointer over the Label, hold down the Control key, and Ctrl-drag from the Label under the class UICollectionViewCell line in the itemCell.swift file.
  4. Release the Control key and the left mouse button. A popup window appears.
  5. Click in the Name text field, type itemLabel, and click the Connect button. Xcode creates an IBOutlet as follows:
@IBOutlet var itemLabel: UILabel!

The entire itemCell.swift file should look like this: import UIKit

class itemCell: UICollectionViewCell {
    @IBOutlet var itemLabel: UILabel! 
}
  1. Choose View > Standard Editor > Show Standard Editor, or click the Standard Editor icon in the upper right corner of the Xcode window.
  2. Click the ViewController.swift file in the Navigator pane.
  3. Edit the class ViewController line as follows:
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {

Type the following underneath the IBOutlet:

let petArray = ["cat", "dog", "parakeet", "parrot", "canary", 
"finch", "tropical fish", "goldfish", "sea horses", "hamster", 
"gerbil", "rabbit", "turtle", "snake", "lizard", "hermit crab"]

Edit the viewDidLoad method as follows:

override func viewDidLoad() {
    super.viewDidLoad()
    collectionView.dataSource = self 
    collectionView.delegate = self
}

Add the following function under the viewDidLoad method:

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return petArray.count 
}

Add the following function under the previous function:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) 
-> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "customCell", 
        for: indexPath) as! itemCell 
    cell.itemLabel.text = petArray[indexPath.row]
    return cell
}

Add the following function under the previous function:

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    let alert = UIAlertController(title: "Your Choice", 
            message: "\(petArray[indexPath.row])", 
            preferredStyle: .alert)
    let action = UIAlertAction(title: "OK", style: .default, handler: nil)
    alert.addAction(action)
    self.present(alert, animated: true, completion: nil) 
}

Displaying Section Headers in a Collection View

The simplest Collection View consists of one section, which displays a grid of items on the screen. However, it’s more likely that data can be divided into two or more groups or sections. When this occurs, a Collection View can display section headers to divide items on the screen.

Creating a section header involves several steps:

  • Enable a section header in the Attributes Inspector pane of the Collection View.
  • Define an arbitrary identifier name for the header.
  • Drag and drop one or more objects into the section header such as a label.
  • Connect the section header objects to IBOutlets in a .swift file.
  • Implement the viewForSupplementaryElementOfKind method to define what appears in the header.

To see how to create and display section headers in a Collection View, follow these steps:

  1. Click the Main.storyboard file in the Navigator pane. Xcode displays the single view.
  2. Click the Library icon to open the Object Library window.
  3. Drag and drop a Collection View anywhere on the view.
  4. Resize the Collection View so it fills the entire screen.
  5. Choose Editor > Resolve Auto Layout Issues > Reset to Suggested Constraints. Xcode adds constraints to the Collection View.
  6. Choose View > Inspectors > Show Size Inspector, or click the Size Inspector icon in the upper right corner of the Xcode window.
  7. Click in the Cell Size Width text field, type 100, and press ENTER.
  8. Click in the Cell Size Height text field, type 100, and press ENTER.
  9. Choose View > Inspectors > Show Attributes Inspector, or click the Attributes Inspector icon in the upper right corner of the Xcode window.
  10. Select the Section Header check box. Xcode creates a Collection Reusable View (section header) in the Document Outline and on the view.
  11. Click in the Background popup menu and choose a color to make the section header easy to see.
  12. Choose File > New > File. A template dialog appears.
  13. Click Cocoa Touch Class under the iOS category and click the Next button. Another dialog appears.
  14. Click in the Class text field, type itemCell, and press ENTER.
  15. Click in the Subclass of popup menu and choose UICollectionViewCell.
  16. Click the Next button. Xcode asks where you want to store the itemCell.swift file.
  17. Click the Create button. Xcode displays the itemCell.swift file in the Navigator pane.
  18. Click Collection Reusable View in the Document Outline and choose View > Inspectors > Show Attributes Inspector, or click the Attributes Inspector icon in the upper right corner of the Xcode window.
  19. Click in the Identifier text field, type headerView, and press ENTER.
  20. Choose View > Inspectors > Show Identity Inspector, or click the Identity Inspector icon in the upper right corner of the Xcode window.
  21. Click in the Class popup menu and choose itemCell.
  22. Click the Collection View Cell in the Document Outline.
  23. Choose View > Inspectors > Show Identity Inspector, or click the Identity Inspector icon in the upper right corner of the Xcode window.
  24. Click in the Class popup menu and choose itemCell.
  25. Choose View > Inspectors > Show Attributes Inspector, or click the Attributes Inspector icon in the upper right corner of the Xcode window.
  26. Click in the Identifier text field, type customCell, and press ENTER.
  27. Click in the Background popup menu and choose a color to make the Collection View Cell easy to see.
  28. Click the Library icon to display the Object Library window.
  29. Drag and drop a label in the center of the cell.
  30. Click the Align icon at the bottom of the Xcode window, select the Horizontally in Container and Vertically in Container check boxes, then click the Add 2 Constraints button.
  31. Click the Library icon to display the Object Library window.
  32. Drag and drop a label in the center of the section header.
  33. Click the Align icon at the bottom of the Xcode window, select the Horizontally in Container and Vertically in Container check boxes, then click the Add 2 Constraints button.
  34. Choose View > Assistant Editor > Show Assistant Editor, or click the Assistant Editor icon in the upper right corner of the Xcode window. The Main.storyboard appears in the left side.
  35. Click the two entwined circles at the top of the Assistant Editor on the right side and choose Manual. Then navigate through the folders to select itemCell.swift.
  36. Move the mouse pointer over the label in the section header, hold down the Control key, and Ctrl-drag under the class ViewController line in the itemCell.swift file.
  37. Release the Control key and the left mouse button. A popup window appears.
  38. Click in the Name text field, type headerLabel, and click the Connect button. Xcode creates an IBOutlet as follows:
@IBOutlet var headerLabel: UILabel!
  1. Move the mouse pointer over the label in the Collection View Cell, hold down the Control key, and Ctrl-drag under the class ViewController line in the itemCell.swift file.
  2. Release the Control key and the left mouse button. A popup window appears.
  3. Click in the Name text field, type itemLabel, and click the Connect button. Xcode creates an IBOutlet as follows:
@IBOutlet var itemLabel: UILabel!

The entire itemCell.swift file should look like this:

import UIKit

class itemCell: UICollectionViewCell {
    @IBOutlet var headerLabel: UILabel!
    @IBOutlet var itemLabel: UILabel! 
}
  1. Choose View > Standard Editor > Show Standard Editor, or click the Standard Editor icon in the upper right corner of the Xcode window.
  2. Click the ViewController.swift file in the Navigator pane.
  3. Modify the class ViewController line by adding UICollectionViewDelegate, UICollectionViewDataSource as follows:
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {

The purpose of this code is to identify the ViewController.swift file as both the delegate and data source for the Collection View.

  1. Underneath the class ViewController line, add the following array:
let petArray = [["Mammal", "cat", "dog", "hamster", "gerbil", "rabbit"], 
["Bird", "parakeet", "parrot", "canary", "finch"], 
["Fish", "tropical fish", "goldfish", "sea horses"], 
["Reptile", "turtle", "snake", "lizard"]]

This petArray consists of four string arrays where the first item in each array defines the section header such as "Mammal" or "Bird".

  1. Click the Main.storyboard file in the Navigator pane.
  2. Choose View > Assistant Editor > Show Assistant Editor, or click the Assistant Editor icon in the upper right corner of the Xcode window. The Main.storyboard appears on the left side and the ViewController.swift file should appear on the right side.
  3. Move the mouse pointer over Collection View in the Document Outline, hold down the Control key, and Ctrl-drag under the class ViewController line in the itemCell.swift file.
  4. Release the Control key and the left mouse button. A popup window appears.
  5. Click in the Name text field, type collectionView, and click the Connect button. Xcode creates an IBOutlet as follows:
@IBOutlet var collectionView: UICollectionView!
  1. Choose View > Standard Editor > Show Standard Editor, or click the Standard Editor icon in the upper right corner of the Xcode window.
  2. Click the ViewController.swift file in the Navigator pane.
  3. Modify the viewDidLoad method as follows:
override func viewDidLoad() {
    super.viewDidLoad()
    collectionView.delegate = self 
    collectionView.dataSource = self
}

Underneath the viewDidLoad method, add the following function to define how many sections appear in the Collection View:

func numberOfSections(in collectionView: UICollectionView) -> Int {
    return petArray.count 
}

Underneath the previous function, add the following function to identify the number of items in each section:

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return petArray[section].count - 1 
}

This function returns a value counting all items in each string array except one because one item in each string array is the section header name such as "Mammal".

Underneath the previous function, add the following function to fill the Collection View with data from the petArray:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) 
-> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "customCell", 
            for: indexPath) as! itemCell 
    cell.itemLabel.text = petArray[indexPath.section][indexPath.row + 1]
    return cell 
}

Underneath the previous function, add the following function to display the item the user selected from the Collection View:

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    let alert = UIAlertController(title: "Your Choice", 
             message: "\(petArray[indexPath.section][indexPath.row + 1])", 
             preferredStyle: .alert)
    let action = UIAlertAction(title: "OK", style: .default, handler: nil)
                alert.addAction(action)
    self.present(alert, animated: true, completion: nil) 
}

Underneath the previous function, add the following function to fill the section headers with the first item in each string array:

func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, 
        at indexPath: IndexPath) -> UICollectionReusableView {
    let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, 
             withReuseIdentifier: "headerView", 
             for: indexPath) as! itemCell
    headerView.headerLabel.text = petArray[indexPath.section][0] 
    return headerView
}