iOS 14 Tutorial: UICollectionView List

In this tutorial, you’ll learn how to create lists, use modern cell configuration and configure multiple section snapshots on a single collection view. By Peter Fennema.

4.8 (12) · 3 Reviews

Download materials
Save for later
Share

In iOS 14, Apple introduced new features for UICollectionView. Lists let you include UITableView-like sections in a UICollectionView. Modern Cell Configuration makes registering and configuring collection view cells easier. And, Section Snapshots allow for multiple sections in a UICollectionView, where each section can have a different layout.

In this tutorial, you’ll learn how to:

  • Create an expandable list using UICollectionLayoutListConfiguration.
  • Use Modern Cell Configuration to configure UICollectionView cells.
  • Use Section Snapshots to add multiple sections to a UICollectionView.
Note: This tutorial assumes you’re familiar with UICollectionViewDiffableDataSource and UICollectionViewCompositionalLayout, introduced by Apple in iOS 13. If you haven’t used these before, check out Collection View and Diffable Data Source and Modern Collection Views with Compositional Layouts.

Without further ado, it’s time to get started!

Getting Started

Download the project materials using the Download Materials button at the top or bottom of this tutorial. Open the starter project in Xcode. Build and run.

Pet Explorer empty screen

You’ll see an empty Pet Explorer screen. It’s part of Get a Pet, an app that displays pets available for adoption. You’ll build on top of this app. In the final version, you can browse through pet categories and select a pet to view its details. Then when you’ve found a pet you like, you can tap Adopt to adopt the pet.

The completed app’s Pet Explorer screen shows the available and adopted pets:

Pet Explorer final screen

Notice the cute dog Diego. When you complete this tutorial, you’ll be the proud owner of this virtual puppy. :]

Open Xcode. Browse around the project. When the app starts, it sets a navigation controller as the initial view controller using a PetExplorerViewController as the root view controller. Open Main.storyboard to check out this setup.

Open PetExplorerViewController.swift to explore this file. PetExplorerViewController‘s collectionView is empty. Later, you’ll populate it with list items that represent pets and pet categories.

Pet.swift has all the data related to pets.

The DataSource typealias is for convenience. You’ll use it later when configuring the UICollectionView data source.

The enum Section represents sections of the UICollectionView for .availablePets and .adoptedPets.

Finally, in the PetExplorerViewController extension, you’ll find pushDetailForPet(_:withAdoptionStatus:). This method presents PetDetailViewController when the user selects an item.

Open PetDetailViewController.swift. It’s a simple view controller class that displays the pet’s image, name and birth year.

Now that you’ve explored the app’s structure, it’s time to learn about UICollectionView lists next.

What is a List?

A list is a table view lookalike in a UICollectionView. You can create a list by applying a configurable UICollectionViewCompositionalLayout to a section of a UICollectionView while using only a small amount of code.

You can configure a list to display hierarchical data, with the possibility to collapse and expand list items or to look similar to a traditional table view. If you need a table view in your app you can either use a list with the UICollectionView API or use the traditional UITableView.

In most cases, a list is easier to create and configure.

Now it’s time to create your first list.

Creating a List

You’ll create a flat list that shows the pet categories. This will be your first table view without using UITableView. For a flat list, the advantages of UICollectionView list over UITableView may not be immediately apparent. Later, when you’ll make the list expandable, you’ll discover the real benefits of using UICollectionView list.

Note: The UICollectionView architecture has a clean separation between layout, presentation and data. The sample code for this tutorial follows this pattern. Every time you add a new feature to Get a Pet, you’ll add a block of code for layout first, then for presentation and finally for data.

Configuring the Layout

With iOS 13, Apple introduced UICollectionViewCompositionalLayout, a new API for building complex layouts. In iOS 14, Apple has added:

static func list(using configuration: UICollectionLayoutListConfiguration) -> 
  UICollectionViewCompositionalLayout

This enables you to create a list layout in one line of code, without the need for detailed knowledge of the UICollectionViewCompositionalLayout API. You can configure the appearance, colors, separators, headers and footers of the list with UICollectionLayoutListConfiguration.

It’s time to apply this to your code:

Open PetExplorerViewController.swift. Add the following method below the line with // MARK: - Functions:

func configureLayout() {
  // 1
  let configuration = UICollectionLayoutListConfiguration(appearance: .grouped)
  // 2
  collectionView.collectionViewLayout =
    UICollectionViewCompositionalLayout.list(using: configuration)
}

This configures the layout of the collectionView. Here, you:

  1. Create a configuration with .grouped appearance. This gives you a layout configuration that looks like a table view.
  2. Next, you create a UICollectionViewCompositionalLayout with list sections, that uses the configuration. You’ll apply this layout to the collectionView.

As you can see, the entire layout configuration is only two lines of code.

Call this method at the end of viewDidLoad() by adding:

configureLayout()

Configuring the Presentation

Now it’s time to create a collection view cell for the list. The cell displays the pet category. You’ll learn about the new way to register cells.

Inside the first PetExplorerViewController extension block, add:

// 1
func categoryCellregistration() ->
  UICollectionView.CellRegistration<UICollectionViewListCell, Item> {
  // 2
    return .init { cell, _, item in
      // 3
      var configuration = cell.defaultContentConfiguration()
      configuration.text = item.title
      cell.contentConfiguration = configuration
  }
}

This is your first encounter with modern cell registration and configuration. Here’s what the code does:

  1. categoryCellregistration() creates a cell registration for a cell of type UICollectionViewListCell and a data item of type Item. This is the modern way of registering collection view cells.
  2. You create the cell registration, passing in a closure to configure the cell. The closure is called when a cell needs to render.
  3. Then you configure the cell. The pet category is available in item.title. Don’t worry if you don’t understand what’s going on yet. This tutorial has an entire section about modern cell configuration.

You’ll call categoryCellregistration() when configuring the data source.

Configuring the Data

You configured the layout and the cells for the collection view. Now you need a mechanism to create these cells based on the underlying data for the collection view. That’s where the data source comes in.

Add the following method to PetExplorerViewController:

func makeDataSource() -> DataSource {
  // 1
  return DataSource(collectionView: collectionView) {
    collectionView, indexPath, item -> UICollectionViewCell? in
    // 2
    return collectionView.dequeueConfiguredReusableCell(
      using: self.categoryCellregistration(), for: indexPath, item: item)
  }
}

Here’s what you did:

  1. You create and return a DataSource, passing in collectionView and a closure that provides a UICollectionViewCell to the data source.
  2. Inside the closure, you ask collectionView to dequeue a UICollectionViewCell. Then you pass the cell registration as a parameter, so collectionView will know which cell type it has to dequeue. categoryCellregistration(), which you created a moment ago, contains the logic for the cell configuration.

Add the following property to PetExplorerViewController:

lazy var dataSource = makeDataSource()

This creates the data source for collectionView when it’s first needed because you used lazy in the declaration.

You configured collectionView‘s layout, presentation and data. Now you’ll populate collectionView with data items.

Still in PetExplorerViewController.swift, add the following method to PetExplorerViewController:

func applyInitialSnapshots() {
  // 1
  var categorySnapshot = NSDiffableDataSourceSnapshot<Section, Item>()
  // 2
  let categories = Pet.Category.allCases.map { category in
    return Item(title: String(describing: category))
  }
  // 3
  categorySnapshot.appendSections([.availablePets])
  // 4
  categorySnapshot.appendItems(categories, toSection: .availablePets)
  // 5
  dataSource.apply(categorySnapshot, animatingDifferences: false)
}

This code uses diffable data source to update the list’s content. Apple introduced diffable data source in iOS 13. The code doesn’t have any new iOS 14 features yet. That’ll change when you make the list expandable and add section snapshots to the list.

With applyInitialSnapshots() you:

  1. Create a categorySnapshot that holds the pet category names.
  2. Then create an Item for each category and add it to categories.
  3. Append .availablePets to categorySnapshot.
  4. Then append the items in categories to .availablePets of categorySnapshot.
  5. Apply categorySnapshot to dataSource.

You’ve added a section and indicated all the elements that belong to that section.

Now, add a call to applyInitialSnapshots() at the end of viewDidLoad():

applyInitialSnapshots()

Build and run.

Pet Explorer group appearance

Congratulations! Here’s your first UICollectionView with a list.

A list supports appearances that match the styles of a UITableView: .plain, .grouped and .insetGrouped. The list you created has the .grouped appearance.

iOS 14 has new appearances for presenting list as sidebars: .sidebar and .sidebarPlain. They’re typically used as the primary view in a split view.

Now you’ll make the list expandable.