The main advantage that UICollectionView has over UITableView is that you have full control over its layout. If you are used to working with UITableView you can get up to speed with UICollectionView fast as a big part of the API looks quite familiar to that of UITableView and the build in layout is great for most use cases. However the exiting part of creating custom layouts will be new and can sometimes get quite complex.

In this blogpost I will share with you the basics of custom collection view layouts and other things I have learned while working with collection views.

What is a UICollectionViewLayout?

A UICollectionViewLayout object is responsible for defining the attributes of all the elements in a collection view. Creating a custom layout allows us to tell the collection view exactly what size elements should have, where the elements should be positioned, if it needs to apply a transform etc. It gives us full control over what the layout should look like.

The layout process

At its core the collection view layout process consists of three steps to get the information it needs on the position and attributes of the elements:

  1. prepareLayout: This function gets called the first time the collection view will lay out its content or when the layout is invalidated for example in case the size of the view changes on device orientation. In this method you usually do setup and pre-calculations.
  2. collectionViewContentSize: The collection view uses this to set up the scrollview contentSize. You typically calculate the content size in the prepare layout method.
  3. layoutAttributesForElementsInRect:: Through this method the collection view asks for the attributes of the cells, supplementary views (e.g. headers and footers) and decoration views (e.g. a background view) that should be visible in the given rect.

Layout performance

Just like with table view performance matters in UICollectionView, especially with custom layouts. As always it is important to profile to find out if there are actual performance problems and what is causing them. However there are a few basic things to consider.

  1. layoutAttributesForElementsInRect:: This functions is called many times as you are scrolling through the collection view. Therefore you don’t want to be slow in calculating which attributes should be displayed in the given rect. A good example is given in the WWDC video A Tour of UICollectionView. In this video the speakers show how to solve a scrolling performance issue by using a binary search algorithm instead of linear search to find the attributes that should be displayed in the given rect.

  2. shouldInvalidateLayout(forBoundsChange:): gets called every time the bounds, size or origin of the collection view changes. As UICollectionView is a subclass of UIScrollView this function will be called frequently during scrolling (as scrolling is a bounds change). Therefore avoid heavy calculations and don’t invalidate the layout more times than necessary.

  3. For collection views that contain up to a few hundred items Apple recommends to precompute the attributes in prepareLayout and cache them in order to avoid doing heavy calculations in the middle of scrolling.

The difference between layoutAttributesForElementsInRect: and layoutAttributesForItem(at:)

Because the names of these methods sound alike it is important to know how they are different from each other so that you will use them correctly. As we saw above the layoutAttributesForElementsInRect: method is used to return all the attributes for the given rect on scroll. For large collection views you could also use this method to on demand prepare the layout attributes. The layoutAttributesForItem(at:) method is used by the collection view to retrieve the attributes for a specific item at a specific index path for example during an update animation.

Defining a custom delegate

When writing a custom layout you sometimes need dynamic information such as the size of a certain item based on its contents. For this you can define a delegate Just like UICollectionViewFlowLayout does with UICollectionViewDelegateFlowLayout. Make sure that your custom delegate protocol extends UICollectionViewDelegate. This way the delegate is automatically set and you can access the delegate from the layout by using its collectionView property.

Conclusion

In this blogpost we went over the core layout process of UICollectionView and some tips and tricks on working with custom layouts. Hopefully this will help you to create beautiful layouts for the collection views in your app.

Contact me on Twitter @kairadiagne if you have any questions, comments or feedback.