Mosaic Layout with đ¤


I started experimenting with the Microsoft Bing embedded Copilot GPT-4 model in order to draft some code that can achieve the layout I would like. I had a custom UICollectionViewLayout in mind, that shows differently sized images in a collage fashion.
Something like MosaicLayout mentioned in the Apple article Customizing Collection View Layouts.
You can find libraries implementing a similar layout (like FMMosaicLayout), so I expected it needs a bit of thinking and would not be straight forward, so I asked AI how to do it!
âCan you write me a Swift implementation for a UIKit subclass of UICollectionViewLayout that achieves a Mosaic Layout?â
Certainly! A mosaic layout for a UICollectionView can be achieved by creating a custom UICollectionViewLayout subclass. In this layout, cells are arranged in a non-conforming grid with varying sizes and aspect ratios. Letâs create a simple example of a mosaic layout in Swift.
Remember to customize the cellHeight calculation based on your data. This example assumes a fixed number of columns, but you can adjust it as needed. Happy coding! đ
The code it generated had some placeholders I had to replace, like the logic for the cellHeight. I set numberOfColumns constant to 2 and used the following logic to achieve the desired look:
// Your logic to determine cell height
let cellHeight = indexPath.row % 3 == 1 ? 94.0 : 44.0
The result is pretty impressive

The image and the title on the content is a placeholder too from AI that I substituted and added an orange background to be able to see the cells.
I used AI again to generate the CustomCollectionViewController I needed to present the cells as well as the CustomCollectionViewCell.
I asked AI to conform CustomCollectionViewControllertoUIViewControllerRepresentable, so I can use it in a preview.
Through my journey I run into a few issues I would like to mention, as I found them odd.
I asked AI to generate the CustomCollectionViewCell which it did and used UIImageView and UILabel subviews with addSubview and NSLayoutConstraint.activate which was expected, so I asked it to use UIContentConfiguration instead. It used defaultContentConfiguration() which is defined on UICollectionViewListCell and not UICollectionViewCell which it subclassed. I asked:
"Xcode says "Cannot find 'defaultContentConfiguration' in scope" can you help me fix this issue?"
It seems like youâre trying to use defaultContentConfiguration() which is a method available in iOS 14 and later for configuring collection view cells. If youâre seeing the error âCannot find âdefaultContentConfigurationâ in scope,â it could be due to a couple of reasons:
iOS Version: Ensure that your projectâs deployment target is set to iOS 14.0 or later since defaultContentConfiguration() is not available in earlier versions.
Import UIKit: Make sure you have imported UIKit at the top of your Swift file
Correct Class: defaultContentConfiguration() is a method on UICollectionViewCell, so make sure your CustomCollectionViewCell is a subclass of UICollectionViewCell.
I'm using iOS 17.0+ that can't be an issue, nor the import. The 3rd option caught my eye as that answer is incorrect according to Apple's documentation, I asked:
"According to Apple's own documentation defaultContentConfiguration() is defined on UICollectionViewListCell, can you suggest a fix for the problem with this in mind?"
You are correct; defaultContentConfiguration() is indeed defined on UICollectionViewListCell, which is a subclass of UICollectionViewCell specifically designed for list-style collection views introduced in iOS 14. If youâre using a standard collection view layout and not a list configuration, you wonât have access to this method.
To fix the issue, you can either:
Use UICollectionViewListCell: If your collection view is intended to display a list, you can change your custom cell to inherit from UICollectionViewListCell instead of UICollectionViewCell. This will give you access to defaultContentConfiguration().
Custom Configuration: If youâre not using a list-style collection view, youâll need to create your own content configuration. You can do this by subclassing UIContentConfiguration and implementing the necessary properties and methods to update your cellâs content.
I feel this might be caused by AI's fuzziness that it doesn't really know if defaultContentConfiguration() is defined on UICollectionViewListCell it just correlated this information roughly to the problem at hand.
Changing the superclass sorted the first problem where I've run into yet another compiler error with the code AI wrote defaultContentConfiguration().updated(for: self) . What I got from Xcode was Argument type 'CustomCollectionViewCell' does not conform to expected type 'UIConfigurationState' . Okay lets ask again:
"I get the error "Argument type 'CustomCollectionViewCell' does not conform to expected type 'UIConfigurationState'" can you help me fix it?"
Certainly! The error message âArgument type âCustomCollectionViewCellâ does not conform to expected type âUIConfigurationStateââ suggests that thereâs a mismatch in the types being used in your code.
The updated(for:) method expects an argument of type UIConfigurationState, but it seems like youâre passing an instance of CustomCollectionViewCell instead. The UIConfigurationState is a protocol that defines the current state of a UI element, such as a cell, and is used to update the configuration accordingly.
To fix this issue, you should pass the correct state object to the updated(for:) method. Hereâs how you can modify the updateConfiguration(using:) method in your CustomCollectionViewCell class:
... // code is removed by author
In this revised method, state is of type UICellConfigurationState, which conforms to UIConfigurationState. This should resolve the type mismatch error youâre encountering.
Make sure that your CustomCollectionViewCell is a subclass of UICollectionViewListCell if youâre using defaultContentConfiguration(), as this method is specific to UICollectionViewListCell.
If you have any further questions or need more assistance, feel free to ask!
Then it gave me the exact same implementation as before without solving the compilation error. I had to read Apple's documentation and use defaultContentConfiguration().updated(for: UICellConfigurationState(traitCollection: traitCollection)) instead. The CustomCollectionViewCell conforming to UIConfigurationState was an odd suggestion as the cell would need to become it's own state manager and would need to implement the subscript(UIConfigurationStateCustomKey) like isSelected: Bool and isHighlighted: Bool that is defined by UICellConfigurationState (which is a class and we can't subclass from two classes).
For every prompt the implementation suggested by AI had some form of compilation error. Easy to solve, but clearly things that would not compile. For example columnHeights was defined as a local variable in func prepare() to calculate and cache the heights of each column and then used in var collectionViewContentSize to calculate the size for the content for the collection where it would not be available in the scope of this computed property.
class MosaicLayout: UICollectionViewLayout {
// ... more code
// Changed this to be a property
private var columnHeights: [CGFloat] = []
override func prepare() {
super.prepare()
// ... more code
// Initialize the y-coordinate for each column
columnHeights = Array(repeating: 0.0, count: numberOfColumns)
// Iterate through each item in the collection view
for item in 0..<collectionView.numberOfItems(inSection: 0) {
// ... more code
// Update column height
columnHeights[shortestColumnIndex] += cellHeight + cellPadding
// ... more code
}
}
override var collectionViewContentSize: CGSize {
guard let lastColumnHeight = columnHeights.max() else { return .zero }
return CGSize(width: collectionView?.bounds.width ?? 0.0, height: lastColumnHeight)
}
}
Another easy, but odd variation of a compilation error was where CustomCollectionViewCell had the reuseIdentifier defined like so
class CustomCollectionViewCell: UICollectionViewListCell {
static let reuseIdentifier = "CustomCollectionViewCell"
// ... more code
}
and in the next iteration when I asked to use content configuration, it had removed the reuseIdentifier making the code not compile on the register.
I wonder if you're working with an AI assistant that has more context like Github Copilot would you run into this back and forth oddities? đ¤ I wouldn't like AI to keep changing my existing code and keep making unwanted changes to my commits.
Until next time, keep coding! đ¨âđť





