UICollectionView
cell spacing
UICollectionViewFlowLayout
iOS development
Swift programming

How to set cell spacing and UICollectionView - UICollectionViewFlowLayout size ratio?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

UICollectionViewFlowLayout gives you control over item size, spacing, and section insets, which is enough to build most grid layouts in iOS. The usual challenge is not setting these values individually, but calculating them together so a fixed number of cells fit cleanly across the available width.

The Three Layout Values That Matter Most

For a basic grid, you usually care about:

  • 'minimumInteritemSpacing for horizontal gaps between items in a row'
  • 'minimumLineSpacing for vertical gaps between rows'
  • 'itemSize for the width and height of each cell'

You often also set sectionInset, because left and right insets affect the width available for items.

swift
1let layout = UICollectionViewFlowLayout()
2layout.minimumInteritemSpacing = 8
3layout.minimumLineSpacing = 12
4layout.sectionInset = UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16)

That configures spacing, but you still need to compute itemSize correctly.

Calculate Item Width from the Available Space

Suppose you want two items per row with an aspect ratio of 3:4. You subtract the total insets and spacing from the collection view width, then divide by the number of columns.

swift
1func itemSize(for width: CGFloat) -> CGSize {
2    let columns: CGFloat = 2
3    let horizontalInset: CGFloat = 16 + 16
4    let interItemSpacing: CGFloat = 8
5
6    let totalSpacing = horizontalInset + (columns - 1) * interItemSpacing
7    let itemWidth = (width - totalSpacing) / columns
8    let itemHeight = itemWidth * 4 / 3
9
10    return CGSize(width: itemWidth, height: itemHeight)
11}

The key idea is that the ratio is applied after you derive the width from the available space. That keeps the grid aligned instead of guessing a fixed width and hoping it fits.

Apply the Size Dynamically

The most flexible approach is to implement UICollectionViewDelegateFlowLayout and calculate the size at runtime.

swift
1import UIKit
2
3final class GridViewController: UIViewController, UICollectionViewDelegateFlowLayout {
4    @IBOutlet weak var collectionView: UICollectionView!
5
6    func collectionView(
7        _ collectionView: UICollectionView,
8        layout collectionViewLayout: UICollectionViewLayout,
9        sizeForItemAt indexPath: IndexPath
10    ) -> CGSize {
11        let columns: CGFloat = 2
12        let inset: CGFloat = 16
13        let spacing: CGFloat = 8
14        let total = inset * 2 + spacing * (columns - 1)
15        let width = (collectionView.bounds.width - total) / columns
16        let height = width * 4 / 3
17        return CGSize(width: width, height: height)
18    }
19}

This is preferable when the collection view can resize, such as during rotation, split view changes, or different device classes.

When a Fixed itemSize Is Enough

If the layout never changes, you can set itemSize directly on the flow layout.

swift
1if let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
2    layout.minimumInteritemSpacing = 8
3    layout.minimumLineSpacing = 12
4    layout.sectionInset = UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16)
5    layout.itemSize = CGSize(width: 150, height: 200)
6}

This is simpler, but it is less adaptive. Fixed values often break on smaller devices or after rotation.

Handling Different Column Counts

Many apps change the number of columns depending on width. For example, two columns on phones and three on tablets.

swift
func numberOfColumns(for width: CGFloat) -> CGFloat {
    return width > 700 ? 3 : 2
}

Combine that with the same spacing formula to keep the layout consistent across device sizes.

Common Pitfalls

A common mistake is computing itemSize without subtracting both section insets and inter-item spacing. That leads to items that look almost correct but do not fit cleanly in a row.

Another mistake is setting minimumInteritemSpacing and expecting UIKit to preserve an exact ratio automatically. The ratio is your responsibility because itemSize still needs to be computed from the available width.

A third mistake is calculating the size once in viewDidLoad and never updating it. Collection view bounds can change after layout, rotation, or container resizing.

Summary

  • Use minimumInteritemSpacing, minimumLineSpacing, and sectionInset together when designing a grid.
  • Compute item width from available collection view width, not from a guessed constant.
  • Apply the height from your desired aspect ratio after width is known.
  • Prefer sizeForItemAt when the layout needs to respond to width changes.
  • Recalculate on size changes so the grid stays aligned across devices and orientations.

Course illustration
Course illustration

All Rights Reserved.