Creating a custom UICollectionViewLayout

Implementing something as big and complex as a custom UICollectionViewLayout looks like quite a challenge for most people. Creating a custom layout involves calculating the position for each and every cell that your collection view will display. You will have to make sure that your code does this as fast and efficiently as possible because your layout code will directly influence the performance of the entire collection view. Luckily, the documentation for implementing a custom layout is pretty good.

If you look at the documentation for UICollectionViewLayout, you can read about its role in a UICollectionView. This information shows that a custom layout requires you to handle layout for cells, supplementary views, and decoration views. Supplementary views are header and footer views. The HelloContacts app doesn't use these views so we can skip those for now. Decoration views are views that aren't related to the UICollectionView data, but are part of the view hierarchy. The only purpose of these views is decoration, as the name already suggests. The HelloContacts app doesn't use these either so we'll skip those as well for the sake of simplicity.

The documentation also outlines methods that any custom layout should implement according to Apple. Not all of these are mandatory. For example, methods that relate to supplementary views or the ones that involve decoration views are completely optional. The methods that we will implement are the ones that affect the cells. The following is a list of all of these methods:

When you scroll further down on the documentation page, you'll find some information about updating layout, which we won't worry about for now. One method you can find in the docs is the prepare method. This method is the perfect method for a UICollectionViewLayout to calculate all of the layout attributes that will be used for all of the cells. Since all cells in the HelloContacts app are of the same size and most users won't have millions of contacts, we can calculate the entire layout in the prepare method. Precalulating the full layout will work perfectly fine for this layout due to the predictable nature of the cells; they are always the same size.

A custom collection view layout is always a subclass of UICollectionViewLayout. The first thing you'll need to do is create a new Cocoa Touch class and name it ContactsCollectionViewLayout. Make sure that your new class inherits from UICollectionViewLayout.

We're going to implement the design in the following screenshot. This design is very similar to a grid layout that scrolls horizontally; the main difference is that all of the odd-numbered rows (if you start counting at 0 like a true iOS master) are indented a bit:

Since all elements in this layout have a predictable size that doesn't depend on any external factors, such as the bounds of the collection view this layout belongs to, all of the heavy lifting will be done in the prepare method. This is where all of the layout attributes for every cell will be calculated so they are available right away whenever the collection view needs to lay out its cells.

The steps required to implement the layout are the following:

  1. Precalculate the layout in the prepare method.
  2. Implement collectionViewContentSize to provide the collection view with enough information to configure its scrolling.
  3. Implement layoutAttributesForElements(_:) to provide the layout attributes for all elements in a certain area.

 

  1. Implement ;layoutAttributesForItem(_:) to provide the layout attributes for a specific item.
  2. Implement shouldInvalidateLayout(_:) to determine whether the layout should invalidate for certain changes in the bounds of the collection view.
  3. Assign the custom layout to the collection view.