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
You are currently viewing page 2 of 4 of this article. Click here to view the first page.

Making the List Expandable

It’s time to add pets to the categories.

Here, you’ll discover the powerful benefits of UICollectionView lists. With a UITableView, you would have to handle taps on category cells and pet cells, maintain the visible and expanded state of cells and write the code that shows or hides the pet cells.

With a UICollectionView list, you only have to provide a hierarchical data structure of categories and pets. The list will take care of the rest. You’ll soon discover how much you can achieve with only a few lines of code.

Pet.swift has the data for all pets and the categories they belong to. There’s no need to change anything in the layout, so you’ll start with the presentation.

Configuring the Presentation

Earlier, you created a cell for a pet category. You learned about the new way to register cells. Here you’ll do the same, this time to create a cell for a pet. The cell will display the pet’s name.

In PetExplorerViewController.swift, add:

func petCellRegistration() ->
  UICollectionView.CellRegistration<UICollectionViewListCell, Item> {
    return .init { cell, _, item in
      guard let pet = item.pet else {
        return
      }
      var configuration = cell.defaultContentConfiguration()
      configuration.text = pet.name
      cell.contentConfiguration = configuration
  }
}

petCellRegistration() is similar to categoryCellregistration() you added earlier. You create a cell registration and use modern cell configuration to configure the cell. Here you use defaultContentConfiguration() and then assign the pet name as the text to display.

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

Next, you’ll make the list expandable by adding an outline disclosure accessory to the category cell. This indicates that an item can expand and collapse. When you tap a category, the list expands and shows the pets for that category.

In categoryCellregistration() and right below cell.contentConfiguration = configuration, add:

// 1
let options = UICellAccessory.OutlineDisclosureOptions(style: .header)
// 2
let disclosureAccessory = UICellAccessory.outlineDisclosure(options: options)
// 3
cell.accessories = [disclosureAccessory]

Here, you:

  1. Create options you want to apply to disclosureAccessory. You use .header style to make the cell expandable.
  2. Then, create a disclosureAccessory with the configured options.
  3. Apply the accessory to the cell. Cells can have more than one accessory, so you add disclosureAccessory in an array.

Build and run.

Pet Explorer disclosure

The outline disclosure is visible, but when you tap a cell, nothing happens. Why? You didn’t add pets to their categories yet. You’ll do that next.

Configuring the Data

Next, you’ll learn how to add hierarchical data to a list. When you’re done, you’ll see that the list automatically supports collapsing and expanding cells.

Now, adapt the data source to add the pet cells to their categories.

In makeDatasource(), replace:

return collectionView.dequeueConfiguredReusableCell(
  using: self.categoryCellregistration(), for: indexPath, item: item)

With:

if item.pet != nil {
  // 1
  return collectionView.dequeueConfiguredReusableCell(
    using: self.petCellRegistration(), for: indexPath, item: item)
} else {
  // 2
  return collectionView.dequeueConfiguredReusableCell(
    using: self.categoryCellregistration(), for: indexPath, item: item)
}

An item can either represent a category or a pet. This depends on the value of pet. In this code, the collectionView will dequeue:

  1. A cell for a pet if item.pet is not nil.
  2. A cell for a category if item.pet is nil.

You configured everything needed to display pets but didn’t add any pets yet. For this to work, you have to update the initial snapshot of the data.

Replace the body of applyInitialSnapshots() with:

// 1
var categorySnapshot = NSDiffableDataSourceSectionSnapshot<Item>()
// 2
for category in Pet.Category.allCases {
  // 3
  let categoryItem = Item(title: String(describing: category))
  // 4
  categorySnapshot.append([categoryItem])
  // 5
  let petItems = category.pets.map { Item(pet: $0, title: $0.name) }
  // 6
  categorySnapshot.append(petItems, to: categoryItem)
}
// 7
dataSource.apply(
  categorySnapshot,
  to: .availablePets,
  animatingDifferences: false)

To build the hierarchical relation between categories and pets you:

  1. Create a categorySnapshot of type NSDiffableDataSourceSectionSnapshot. This is a section snapshot. With a section snapshot it’s possible to represent data with a hierarchical structure, such as an outline with expandable items.
    For now, this is all you need to know about section snapshots. You’ll learn more about section snapshots later in this tutorial.
  2. Then, loop over the categories in Pet.Category.allCases. Within the loop, you add the pets to their categories.
  3. Create a categoryItem.
  4. Append the categoryItem to the categorySnapshot.
  5. Then, create an array, petItems, containing all pets that belong to the current category.
  6. Create the hierarchical relationship between categories and pets by appending the petItems to the current categoryItem.
  7. Apply categorySnapshot to .availablePets of dataSource.

Build and run.

Pet Explorer disclosure expanded

Tap a category. The list expands and shows the pet names. Great!

Now it’s time to make the cells look a little better.

What is Modern Cell Configuration?

If you’ve used a UITableView or UICollectionView, you’re used to configuring your cells by directly setting their properties. In iOS 14, cell configuration can be entirely decoupled from the cell itself.

You create a cell content configuration of type UIContentConfiguration. Then, you set the properties of this content configuration as you like. Similarly, you can create a cell background configuration of type UIBackgroundConfiguration.

The result is a reusable configuration you can apply to any cell you like.

It’s time to see how this works!

Configuring the Cells

You just learned the theory of modern cell configuration. Now, you’ll put cell content configuration into practice by adding code to update the pet cell to show a pet’s image and age. In the next section, you’ll apply cell background configuration.

In petCellRegistration(), replace:

var configuration = cell.defaultContentConfiguration()
configuration.text = pet.name
cell.contentConfiguration = configuration

With:

// 1
var configuration = cell.defaultContentConfiguration()
// 2
configuration.text = pet.name
configuration.secondaryText = "\(pet.age) years old"
configuration.image = UIImage(named: pet.imageName)
// 3
configuration.imageProperties.maximumSize = CGSize(width: 40, height: 40)
// 4
cell.contentConfiguration = configuration

Here, you see cell content configuration in action. You:

  1. Create a configuration of type UIListContentConfiguration with default styling. With this configuration, you have a cell where you can set an image, text and secondary text.
  2. Apply the pet’s data to the configuration, including an image of the pet.
  3. Set the size of the image.
  4. Apply configuration to contentConfiguration of the cell.

Build and run.

Pet Explorer images

Suddenly, the pets look more cuddly. Are you feeling motivated to adopt one? :]