Categories
iOS Swift UIKit

UICollectionViewFlowLayout and auto layout on iOS

UICollectionViewFlowLayout is layout object supplied by UIKit and enables showing items in grid. It allows customising spacings and supports fixed size cells and cells with different sizes. This time I am going to show how to build a collection view containing items with different sizes where sizes are defined by auto layout constraints.

Cell sizes in UICollectionViewFlowLayout

By default UICollectionViewFlowLayout uses itemSize property for defining the sizes of the cells. Another way is to use UICollectionViewDelegateFlowLayout and supplying item sizes by implementing collectionView(_:layout:sizeForItemAt:). Third way is to let auto layout for defining the size of the cell. This is what I am going to build this time.

Enabling auto layout based cell sizes

When setting UICollectionViewFlowLayout’s estimatedItemSize to UICollectionViewFlowLayout.automaticSize enables layout object to use auto layout.

final class CollectionViewController: UICollectionViewController {
let content: [String]
init(content: [String]) {
self.content = content
let layout = UICollectionViewFlowLayout()
layout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
super.init(collectionViewLayout: layout)
}
}

Setting up collection view cell with auto-layout constraints

When layout object is configured, second step is to create a cell. In the current prototype it is going to be a simple cell with a label and border around the label. Constraints are set up to have a 8 points space around the label. Constraints together with label’s intrinsicContentSize define the minimum size for the cell. If text is longer, intrinsicContentSize is wider.

final class TextCollectionViewCell: UICollectionViewCell {
let textLabel: UILabel
override init(frame: CGRect) {
textLabel = {
let label = UILabel(frame: .zero)
label.adjustsFontForContentSizeCategory = true
label.font = UIFont.preferredFont(forTextStyle: .body)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
super.init(frame: frame)
contentView.addSubview(textLabel)
NSLayoutConstraint.activate([
textLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8),
textLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -8),
textLabel.topAnchor.constraint(equalTo: topAnchor, constant: 8),
textLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8)
])
contentView.layer.borderColor = UIColor.darkGray.cgColor
contentView.layer.borderWidth = 1
contentView.layer.cornerRadius = 4
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

When putting all the things together, the end result is a collection view where every cell has its own size. Moreover, it supports dynamic type and cells will grow if user changes default text sizes.

Summary

UICollectionViewFlowLayout’s estimatedItemSize enables using auto-layout for defining cell sizes. Therefore creating cells where text defines the size of the cell is simple to do on iOS.

If this was helpful, please let me know on Mastodon@toomasvahter or Twitter @toomasvahter. Feel free to subscribe to RSS feed. Thank you for reading.

Example project

FittingCellsInCollectionViewFlowLayout Xcode 10.2, Swift 5.0

Resources

One reply on “UICollectionViewFlowLayout and auto layout on iOS”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s