Implementing a Dynamic Height UICollectionViewCell in Swift 5
Creating a UICollectionViewCell to have a dynamic height based on font size and image aspect ratio
The Problem
Sometimes we need to be UICollectionView’s Cells have size depend on their content and the most common example is the feeds in social websites every post has a different size as well as their comments.
I’ve searched for a solution many of them didn’t work on iOS 14 & Swift 5 and some depend on third-party libraries so I decided to write this article.
This tutorial has two parts. First, We’re going to implement a self-sizing UICollectionViewCell
based on font size as shown in the screenshot on the left side.
Second we’re going to build a dynamic height UICollectionViewCell
based on the image aspect ratio in addition to font size the result will be like the right side of the screenshot.
Part1: Self-Sizing UICollectionViewCell
based on font size only
It consists of three steps the first is creating and configuring the cell then we’re going to subclass UICollectionViewFlowLayout
after that, we would configure UICollectionView
.
Step 1: Create and Configure UICollectionView Cell
We’re going to create a simple cell to display a photo as well as the name of the user and his comment.
Please notice that I’ve used an extension to set up Auto layout Constrains you can check out this link
Now we should modify the cell’s frame in order to set a dynamic size based on the font size to do so we have to override preferredLayoutAttributesFitting method so copy the snippet below to our custom cell.
layoutAttributes
are the values which would be applied on the cell
Step 2: Subclass UICollectionViewFlowLayout
Step 3: Configure UICollectionView
In the last step, we have to set up our UICollectionView
with an instance of CommentFlowLayout
class to do so just paste the code below at viewDidLoad method.
Part2: UICollectionViewCell Height
based on the image aspect ratio and font size
We‘re going to display two columns in the row so we have to calculate the cell’s positions manually in our subclassed UICollectionViewFlowLayout
because we have different heights.
To do so we’ll adapt a nice solution was introduced by the raywenderlich team they implement a dynamic cell based on photo height you can check out the article here, however, we want to size the UICollectionViewCell
based on the aspect ratio of the photo and the font.
Step 1: Create and Configure UICollectionView Cell
We’re going to create the feed cell to display a photo and dummy description text below it.
Notes:
- We’ve set up setContentHuggingPriority for the
label
to high value because we need to have size only to display the content, unlike theUIImageView
we assigned to a low value to get the remaining space - We assigned zero to
numberOfLines
of the label in order to display multiline and we initialized thelineBreakMode
property with byWordWrapping value.
We should add constraints to our cell so add this function to FeedCell
and then call it after setupViews
function
Notice that first, we pinned the photo to the four edges of the contentView
after that, we linked the description lable
with the bottom of the photo with a 5 margin.
Step 2: Subclass UICollectionViewFlowLayout
Create a class called it PinterestLayout then paste the code below
Notes:
- We’ve introduced a delegate to communicate with our ViewController in order to get the cell’s height
- In prepare function, we calculated the cell’s size and their position then we cashed them instead of recalculating the attributes every time.
Step 3: Configure UICollectionView
We have to create and an instance of our PinterestLayout
class then assign it as a layout to the UICollectionView.
The Tricky part
We need to confirm our protocol PinterestLayoutDelegate
that we had created earlier which ask our ViewController about the height of the cell but how will we calculate it?
We‘re going to write two functions one to calculate the appropriate photo’s height and another to calculate the required space to display the description so let’s start with the first one.
Here we need our API to provide so important information to help us figure out the perfect size based on the image aspect ratio to do so the backend developer must supply the dimensions of the photo as shown below
So we figured out the new height based on the old dimension in addition to the cell width.
Now let’s move to the second function calculating text’s space needed we’ll create a fake Lable
then place our text after that the function will return the Lable’s height
Notes:
- You have to use the same font attributes as well as the
lineBreakMode
value that was set up in the first step when we created the custom cell - You must call
sizeToFit
function
Merge the pieces together
Now we are ready to satisfy Xcode and make it stop complaining about PinterestLayoutDelegate
protocol.
Notes:
- We’ve added 5 value into the total because earlier at design the custom cell we had left margin between the photo and the label.
- Headers are a dummy string array was generated using Fakery
The Conclusion
We’ve implemented two approaches to create UICollectionViewCell with dynamic height programmatically based on its content which is compatible with Swift 5 without any third-party, First one was based on the font size, while the second was based on photos’ size that was fed via API in addition to the description text‘s size.
I published the source code on GitHub.
Further reading :
Extending UICollectionView with a Centered UIActivityIndicatorView
Adding a loading indicator to your infinite UICollectionView
Creating a native popup menu over a UIButton or UINavigationBar