Skip to main content

Working with Collection Views

1. Creating UICollectionView

Property Value Description
UICollectionView UICollectionView(frame: CGRect, collectionViewLayout: UICollectionViewLayout) Initializes a collection view with a specified frame and layout
dataSource UICollectionViewDataSource Provides the data and views for the collection view
delegate UICollectionViewDelegate Handles user interactions and layout customization

Example: Basic UICollectionView Setup

import UIKit

class ViewController: UIViewController {
    @IBOutlet weak var collectionView: UICollectionView!

    override func viewDidLoad() {
        super.viewDidLoad()
        setupCollectionView()
    }

    func setupCollectionView() {
        let layout = UICollectionViewFlowLayout()
        layout.itemSize = CGSize(width: 100, height: 100)
        collectionView.collectionViewLayout = layout
        collectionView.dataSource = self
        collectionView.delegate = self
    }
}

extension ViewController: UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 10
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
        return cell
    }
}

extension ViewController: UICollectionViewDelegate {
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        print("Selected item at index path: \(indexPath)")
    }
}

2. Implementing UICollectionViewDataSource

Method Description Return Type Notes
numberOfSections(in:) Number of sections in the collection view Int Required
collectionView(_:numberOfItemsInSection:) Number of items in a section Int Required
collectionView(_:cellForItemAt:) Configure and return a cell for a specific item UICollectionViewCell Required
collectionView(_:viewForSupplementaryElementOfKind:at:) Return supplementary views (headers/footers) UICollectionReusableView Optional

Example: Basic UICollectionViewDataSource Implementation

class MyDataSource: NSObject, UICollectionViewDataSource {
    let items = ["Item 1", "Item 2", "Item 3"]
    
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return items.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
        cell.textLabel?.text = items[indexPath.item]
        return cell
    }
}
Note: The UICollectionViewDataSource protocol is required for any collection view to display content. It provides the data and cells needed to render items.

3. Implementing UICollectionViewDelegate

Method Description Return Type Notes
collectionView(_:didSelectItemAt:) Called when a cell is selected Void Use to handle selection logic
collectionView(_:didDeselectItemAt:) Called when a cell is deselected Void Use to handle deselection logic
collectionView(_:willDisplay:forItemAt:) Called just before a cell is displayed Void Use for animations or updates
collectionView(_:didEndDisplaying:forItemAt:) Called after a cell is removed from display Void Use for cleanup or animation reset
collectionView(_:shouldHighlightItemAt:) Controls whether a cell can be highlighted Bool Return false to disable highlighting
collectionView(_:shouldSelectItemAt:) Controls whether a cell can be selected Bool Return false to disable selection
collectionView(_:shouldDeselectItemAt:) Controls whether a cell can be deselected Bool Return false to prevent deselection
collectionView(_:contextMenuConfigurationForItemAt:point:) Provides context menu configuration for a cell UIContextMenuConfiguration? Available from iOS 13+

Example: Handling Cell Selection

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    let item = items[indexPath.item]
    print("Selected item: \(item)")
}

Example: Customizing Highlight Behavior

func collectionView(_ collectionView: UICollectionView, shouldHighlightItemAt indexPath: IndexPath) -> Bool {
    return indexPath.item != 0 // Prevent highlighting first item
}

4. Creating Custom Collection View Layouts

Example: Basic Custom Layout Class

import UIKit

class CustomCollectionViewLayout: UICollectionViewFlowLayout {
    override func prepare() {
        super.prepare()
        itemSize = CGSize(width: 100, height: 100)
        minimumInteritemSpacing = 10
        minimumLineSpacing = 10
    }
    
    override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
        return true
    }
}
Property Description Default Value
itemSize Size of each collection view item CGSize(width: 50, height: 50)
minimumInteritemSpacing Minimum spacing between items in a row 0
minimumLineSpacing Minimum spacing between lines 0
scrollDirection Scroll direction of the collection view .vertical
headerReferenceSize Size of the header view CGSize(width: 0, height: 0)
footerReferenceSize Size of the footer view CGSize(width: 0, height: 0)
Note: Custom layouts should override prepare to calculate layout attributes and shouldInvalidateLayout(forBoundsChange:) to determine when to recalculate.
Warning: Layout calculations must be efficient to avoid performance issues during scrolling.

Key Points

  • Custom layouts inherit from UICollectionViewLayout
  • Override prepare to calculate layout attributes
  • Use shouldInvalidateLayout(forBoundsChange:) to control layout updates
  • Implement layoutAttributesForElements(in:) to return layout attributes

5. Using UICollectionViewFlowLayout

Property Values Description
itemSize CGSize Size of each collection view item
minimumLineSpacing CGFloat Minimum spacing between lines of items
minimumInteritemSpacing CGFloat Minimum spacing between items in a line
sectionInset UIEdgeInsets Insets for the section's content area
scrollDirection UICollectionView.ScrollDirection Scroll direction of the collection view (horizontal or vertical)

Example: Setting up UICollectionViewFlowLayout

let flowLayout = UICollectionViewFlowLayout()
flowLayout.itemSize = CGSize(width: 100, height: 100)
flowLayout.minimumLineSpacing = 10
flowLayout.minimumInteritemSpacing = 5
flowLayout.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
flowLayout.scrollDirection = .vertical
Note: UICollectionViewFlowLayout is the default layout for collection views and is ideal for grid-like layouts.

6. Configuring Item Size and Spacing

Property Values Description
itemSize CGSize Defines the size of each item in the collection view.
minimumLineSpacing CGFloat Minimum spacing between lines of items.
minimumInteritemSpacing CGFloat Minimum spacing between items in the same line.
sectionInset UIEdgeInsets Insets for the entire section, applied to all items.

Example: Setting Item Size and Spacing

let layout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width: 100, height: 100)
layout.minimumLineSpacing = 10
layout.minimumInteritemSpacing = 5
layout.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
collectionView.collectionViewLayout = layout

7. Implementing Section Insets

Property Value Description
sectionInset UIEdgeInsets Insets for the entire section content area
minimumLineSpacing CGFloat Minimum spacing between lines in the collection view
minimumInteritemSpacing CGFloat Minimum spacing between items in the same line

Example: Setting Section Insets

let layout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
layout.minimumLineSpacing = 5
layout.minimumInteritemSpacing = 5

let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
Note: sectionInset defines the space around the content of a section, including headers and footers.

8. Using Supplementary Views

Supplementary views in iOS Collection Views are used to display additional content that is associated with a section or item, such as headers or footers.

View Type Description Usage
UICollectionReusableView Base class for supplementary views Subclass to create custom supplementary views
UICollectionViewElementKindSectionHeader Identifier for section header views Used in dequeueReusableSupplementaryView
UICollectionViewElementKindSectionFooter Identifier for section footer views Used in dequeueReusableSupplementaryView

Example: Registering and Using a Header View

class HeaderView: UICollectionReusableView {
    let label = UILabel()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupView()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupView()
    }
    
    private func setupView() {
        label.text = "Section Header"
        label.translatesAutoresizingMaskIntoConstraints = false
        addSubview(label)
        NSLayoutConstraint.activate([
            label.centerXAnchor.constraint(equalTo: centerXAnchor),
            label.centerYAnchor.constraint(equalTo: centerYAnchor)
        ])
    }
}

// Register the header view
collectionView.register(HeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "HeaderView")

// Dequeue the header view in your data source
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, withReuseIdentifier: String, at indexPath: IndexPath) -> UICollectionReusableView {
    let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "HeaderView", for: indexPath) as! HeaderView
    return header
}
Note: Supplementary views must be registered before they can be dequeued. The kind parameter determines whether it's a header or footer.
Warning: Make sure to use unique reuse identifiers for different supplementary view types to prevent incorrect views from being reused.

9. Implementing Cell Selection

Property Value Description
allowsSelection true Enables or disables selection in the collection view
allowsMultipleSelection false Allows multiple cells to be selected at once
indexPathForSelectedItems IndexPath? Returns the index paths of selected items

Example: Selecting a Cell

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    print("Selected item at path: \(indexPath)")
}

Example: Deselecting a Cell

func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
    print("Deselected item at path: \(indexPath)")
}
Note: To enable selection, set allowsSelection to true.
Warning: Ensure that didSelectItemAt and didDeselectItemAt are implemented to handle selection changes.

10. Using Compositional Layout

Property Description Values
sectionInset Insets for the section content UIEdgeInsets
minimumLineSpacing Minimum spacing between lines CGFloat
minimumInteritemSpacing Minimum spacing between items CGFloat

Example: Creating a Compositional Layout

let layout = UICollectionViewCompositionalLayout { (sectionIndex, layoutEnvironment) -> NSCollectionLayoutSection? in
    let itemSize = NSCollectionLayoutSize(
        widthDimension: .fractionalWidth(1.0),
        heightDimension: .absolute(50)
    )
    let item = NSCollectionLayoutItem(layoutSize: itemSize)
    
    let groupSize = NSCollectionLayoutSize(
        widthDimension: .fractionalWidth(1.0),
        heightDimension: .absolute(50)
    )
    let group = NSCollectionLayoutGroup.horizontal(
        layoutSize: groupSize,
        subitems: [item]
    )
    
    let section = NSCollectionLayoutSection(group: group)
    section.contentInsets = .init(top: 10, leading: 10, bottom: 10, trailing: 10)
    return section
}
Note: Compositional layouts provide a more flexible and powerful way to define collection view layouts compared to the older UICollectionViewFlowLayout.
Warning: Ensure that the UICollectionViewCompositionalLayout is properly configured to avoid layout issues or performance problems.

11. Implementing Diffable Data Source

Example: Setting up Diffable Data Source

import UIKit

class ViewController: UIViewController {
    @IBOutlet weak var collectionView: UICollectionView!
    
    private var dataSource: UICollectionViewDiffableDataSource<Section, Item>!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupDataSource()
    }
    
    private func setupDataSource() {
        dataSource = UICollectionViewDiffableDataSource<Section, Item>(collectionView: collectionView) { (collectionView, indexPath, item) -> UICollectionViewCell? in
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
            // Configure cell with item
            return cell
        }
    }
    
    private func updateUI() {
        var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
        snapshot.appendSections([.main])
        snapshot.appendItems([Item(title: "First Item")], toSection: .main)
        dataSource.apply(snapshot, animatingDifferences: true)
    }
}
Property Description Notes
UICollectionViewDiffableDataSource Manages collection view data with diffable updates Replaces older UITableViewDataSource approach
NSDiffableDataSourceSnapshot Represents current state of data in collection view Used to apply updates via apply()
apply(snapshot:animatingDifferences:) Applies snapshot to collection view with animation Supports animating changes between snapshots
Note: UICollectionViewDiffableDataSource requires iOS 13.0+ and is not available in earlier versions.
Warning: When using apply(), ensure that all items and sections are properly registered with the collection view.

Key Features

  • Supports animated updates to collection view content
  • Automatically handles diffing between snapshots
  • Improves performance over manual reloadData()

Was this article helpful?