[SC]()

iOS. Apple. Indies. Plus Things.

UICollectionView with UIContentConfiguration for Cells, Compositional List Layout and Diffable Datasource.

// Written by Jordan Morgan // Apr 25th, 2022 // Read it in about 2 minutes // RE: Snips

This post is brought to you by Emerge Tools, the best way to build on mobile.

let concatenatedThoughts = """

Welcome to Snips! Here, you'll find a short, fully code complete sample with two parts. The first is the entire code sample which you can copy and paste right into Xcode. The second is a step by step explanation. Enjoy!

"""

The Scenario

Create a UICollectionView with all of the modern APIs:

  1. Content configurations to display data.
  2. Compositional layouts to create a list layout.
  3. Diffable datasource.
  4. And modern cell registration methods, forgoing classic APIs such as identifiers and UICollectionViewDatasource.
import UIKit

struct VideoGame: Hashable {
    let id = UUID()
    let name: String
}

extension VideoGame {
    static var data = [VideoGame(name: "Mass Effect"),
                       VideoGame(name: "Mass Effect 2"),
                       VideoGame(name: "Mass Effect 3"),
                       VideoGame(name: "ME: Andromeda"),
                       VideoGame(name: "ME: Remaster")]
}

class ContentConfigViewController: UIViewController {
    // 1
    private lazy var collectionView: UICollectionView = {
        var listConfiguration = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
        
        let layout = UICollectionViewCompositionalLayout.list(using: listConfiguration)
        let collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
        collectionView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
        collectionView.backgroundColor = .systemGroupedBackground
        
        return collectionView
    }()
    
    lazy var datasource: UICollectionViewDiffableDataSource<Int, VideoGame> = {
        // 2
        let videoGameCellConfig = UICollectionView.CellRegistration<UICollectionViewListCell, VideoGame> { cell, indexPath, model in
            var contentConfiguration = cell.defaultContentConfiguration()
            contentConfiguration.text = model.name
            contentConfiguration.textProperties.font = .preferredFont(forTextStyle: .headline)
            cell.contentConfiguration = contentConfiguration
        }
                
        // 3
        let datasource = UICollectionViewDiffableDataSource<Int, VideoGame>(collectionView: collectionView) { collectionView, indexPath, model in
            let configType = videoGameCellConfig
            return collectionView.dequeueConfiguredReusableCell(using: configType,
                                                                for: indexPath,
                                                                item: model)
        }
            
        return datasource
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(collectionView)
        
        // 4
        var snap = datasource.snapshot()
        snap.appendSections([0])
        snap.appendItems(VideoGame.data)
        datasource.apply(snap)
    }
}

Now, we’ve got collection view prepared with all of the modern APIs:

Demo of UICollectionView showing data prepared with modern APIs such a UIContentConfiguration and UICollectionViewDiffableDatasource.

The Breakdown

Step 1
First, we create the collection view by giving it a layout. This process is two-fold:

  1. Create the list configuration via UICollectionLayoutListConfiguration.
  2. Pass it to a compositional layout object, UICollectionViewCompositionalLayout.list(using: listConfiguration).

Then, we can create the collection view with a list layout, UICollectionView(frame: view.bounds, collectionViewLayout: layout).

Step 2
Using modern cell registration, we pass a content configuration object and assign it to a cell. This is where developers typically would use something like func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell to set data from a model to the cell. Here, we grab the default configuration and set a string and adjust the font size.

Step 3
Now, our job is to return the cell registration we just created to the diffable datasource:

return collectionView.dequeueConfiguredReusableCell(using: configType,
                                                      for: indexPath,
                                                     item: model)

At this point, we know what to show for the data we have, and we know how to vend that data.

Step 4
Finally, we create a diffable datasource snapshot and add some data to it and we’re done! We’ve now used all of the modern APIs for UICollectionView.

Until next time ✌️

···

Spot an issue, anything to add?

Reach Out.