There are a lot of resources available about
UICollectionView since the release in iOS 6.0. But most of them use the somewhat basic layout features with
UICollectionViewDelegateFlowLayout. It for example only allows you to scroll horizontally or vertically. But what if you want both? What if you have an advanced and dynamic layout? That's where
UICollectionViewLayout comes in to play.
This is a short guide to help you understand
UICollectionViewLayout. I suggest you check out UICollectionViewWaterfallLayout on GitHub after reading this. It covers all the basics that you'll need to get started with
I've also created a sample Xcode project (see screenshot above) that implements
UICollectionViewLayout. Get it here.
UICollectionViewLayout has a different flow compared to
UICollectionViewDelegateFlowLayout, which is similar to
UITableViewDelegate where you for example provide heights for the cells and more.
You need to provide the position and the size for each item when you use
UICollectionViewLayout. You do this by providing
UICollectionViewLayout for each item in your collection view.
An UICollectionViewLayoutAttributes object manages the layout-related attributes for a given item in a collection view. Layout objects create instances of this class when asked to do so by the collection view. In turn, the collection view uses the layout information to position cells and supplementary views inside its bounds.
UICollectionViewLayoutAttributes is the only object that determines the size and position of the cell. You should not confuse this with your
UICollectionViewDataSource which should only set the content for the cell. It's important to separate these two.
Implementation of UICollectionViewLayout
The first thing you'll need to do is to subclass
UICollectionViewLayout and connect it with your collection view. You can do this in
UICollectionView's init method
To get the basics to work you need to at least override these three methods in your
You return the contentSize in the first method and the
UICollectionViewLayoutAttributes in the last two methods. You could calculate the attributes for an item 'on-the-fly' but
UICollectionViewLayout comes with a method called
prepareLayout where it gives you a chance to pre-calculate the attributes for all items inside the collection view.
UICollectionView will call
prepareLayout when the collection view presents itself for the first time and each time the layout is invalidated (you can manually invalidate the layout by calling 'invalidateLayout' on the
During each layout update, the collection view calls this method first to give your layout object a chance to prepare for the upcoming layout operation.
You should use prepareLayout to calculate the attributes for all your items and store these calculated attributes somewhere in your
UICollectionViewLayout subclass so you can return the attributes when
Horizontal and vertical scrolling
During the implementation of
UICollectionViewLayout you are entirely responsible for the
contentSize of the
UICollectionView. Since you are pre-calculating all the attributes in
prepareLayout you also know how big the content size will be. Simply provide a width and height that's larger than the
UICollectionView bounds to enable both horizontal and vertical scrolling. There's an example in my example project.
- WWDC 2012 Video: Advanced Collection Views and Building Custom Layouts
- Creating Custom Layouts (Apple Docs)
- UICollectionViewWaterfallLayout on GitHub
Also check out my example project to get you started.