Define your own layouts
Whenever I use a storyboard or XIB file to create a custom
UITableView cell layout, I always wonder, wouldn’t it be great if I could use SwiftUI to define the layout? In this year’s WWDC (2022), Apple finally made that happen.
In this article, we will explore what it takes to build the following list using a collection view and SwiftUI.
At the end of this article, you will learn:
- How to use the
- How to adjust the cell height
- How to adjust the separator inset
- How to adjust the cell’s layout margin
There are many topics to be covered here, so let’s get right into it.
Before diving into the main topic, there are a few things that we need to get in place. First, import the SwiftUI module to your view controller class.
After that, define the following data types that will act as the data model of our list:
Next up, configure our collection view to use a list layout configuration.
In the code above, notice that we are not using a diffable data source. A diffable data source is not mandatory when creating a custom cell using SwiftUI. Furthermore, since the list we are building shows a static data set, using a traditional data source is much more straightforward and easier to understand.
Lastly, let’s implement the required
swiftUICellRegistration used in the code above, we will be working on that in a moment. For now, just keep in mind that using the
swiftUICellRegistration is how we link up our custom SwiftUI cell with the collection view.
With all that out of the way, we can now get into the fun stuff.
Before iOS 16, to create a custom
UICollectionViewListCell, we need to create a subclass of
UICollectionViewListCell and define a custom configuration object that conforms to the
UIContentConfiguration protocol, which is somewhat troublesome.
With the introduction of
UIHostingConfiguration in iOS 16, it is now possible to define the layout and content of a custom cell using SwiftUI, eliminating the need to create a
UICollectionViewListCell subclass and a custom configuration object.
Based on Apple’s documentation, the
UIHostingConfiguration struct is conformed to the
UIContentConfiguration protocol. Therefore we can use it during cell registration like so:
From the code above, there are two things you need to be aware of.
First, the cell type that we use for cell registration is
UICollectionViewCell). Since we are building a list, using
UICollectionViewListCell will gain us some of its useful functionalities such as:
- The ability to display cell accessories
- The ability to adjust the separator inset (more on that later)
- Various cell appearances (based on the collection view’s layout configuration)
Second, notice that we are defining the cell registration as an instance variable (
swiftUICellRegistration). As you have seen earlier, this enables us to use
swiftUICellRegistration in the collection view’s data source method.
OK, enough said. Let’s define the cell’s layout and content using SwiftUI to see everything in action.
At this point, if you try to run the sample code, you will see the following cells being populated.
Adjusting the cell height
From the image above, you should notice that our current cell height is a bit smaller than what we are expecting. As mentioned in one of my previous articles,
UICollectionViewListCell is a self-sizing cell. This means it will automatically adjust its size based on its layout and content.
With that in mind, we can easily increase the cell height by simply increasing the height of the
Note: Make sure to set the
HStack‘s frame before setting the yellow color background view, or else the yellow background view height will not increase accordingly.
Here’s the end result:
Adjusting the separator inset
Currently, the separator’s leading edge is aligned with the text in the cell. This is the default behavior inherited from the
UICollectionViewListCell. Unfortunately, this is not what we want.
To achieve what we want, we can use the
alignmentGuide modifier like so:
What the above code did was align the separator leading edge with the
HStack leading edge and align the separator trailing edge with the
HStack trailing edge. Here’s what we will get:
Adjusting the cell’s layout margins
By default, the cell’s SwiftUI content is inset from the edges of the cell, based on the cell’s layout margins in UIKit. To overwrite the default margin, we can use the
margins modifier to do so.
With that, our custom cell has reached its final form.
Now that we have finished composing our custom cell using SwiftUI, we can perform simple refactoring by creating a dedicated SwiftUI view for our custom cell layout.
With that in place, we can now create the
UIHostingConfiguration like so:
Notice how we configure the
MyFirstSwiftUICell‘s content by passing in the
itemobject during initialization.
With this simple refactoring, we have successfully improved the readability of our code when creating a
UIHostingConfiguration. Furthermore, we also converted our custom cell’s layout into a reusable component.
The example I use throughout this article is mainly focused on creating a custom
UICollectionViewListCell, but that doesn’t mean that you cannot use
UIHostingConfiguration to create a custom
UICollectionViewCell. In fact, according to Apple,
UIHostingConfiguration is designed to be able to work on both
However, do notice that
UIHostingConfiguration is only available in iOS 16 and above. If your app still needs to support an iOS version lower than iOS 16, you might consider falling back to the non-SwiftUI way.
Last but not least, here’s the full sample code.
Thanks for reading.
Want to Connect?Reach me out on Twitter if you have any questions.