Creating a custom UICollectionViewLayout

Implementing a large and complex feature such as a custom collection view layout might seem like a huge challenge for most people. Creating your layout involves calculating the position for every cell that your collection view will display. You must ensure that these calculations are performed as quickly and efficiently as possible because your layout calculations directly influence the performance of your collection view. A poor layout implementation will lead to slow scrolling and a lousy user experience eventually. Luckily, the documentation that has been provided for creating a collection view layout is pretty good as a reference to figure out if you're on the right track.

If you take a look at Apple's documentation on UICollectionViewLayout, you can read about its role in a collection view. The available 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 Hello-Contacts app does not use headers and footers in its collection view so these views can be skipped. Decoration views are views that don't correspond with any data in the collection view's data source, but they are part of the collection view's layout. The purpose of these views is purely decorative, just like the name decoration view suggests. Since these views are also not used by Hello-Contacts, the focus will be on the collection view cells only. This makes sure that the implementation remains simple and understandable.

In addition to listing the kinds of views you should layout, the documentation also mentions several methods that should be implemented for any custom layout. Note that not all of these methods are mandatory. For instance, any method that relates to supplementary and decoration views can be omitted if you don't need them. The methods and properties that you need to implement for your custom grid of collection view cells are the following:

  • collectionViewContentSize
  • layoutAttributesForElements(in:)
  • layoutAttributesForItem(at:)
  • shouldInvalidateLayouts(forBoundsChange:)
  • prepare()

Further down in the documentation page for UICollectionViewLayout, you can find some information about updating the layout. For now, you won't bother implementing this, but it's most certainly worth it to familiarize yourself with all of the available documentation. The prepare() method is a very interesting one. It provides a great opportunity for developers to pre-calculate a collection view's layout. Since all cells in Hello-Contacts are the same size, the entire layout for the collection view can be calculated in prepare(). In this case, it's a great choice to do this due to the extremely predictable nature of the layout.

A custom collection view layout always is a subclass of UICollectionViewLayout. To make your layout object, create a new Cocoa Touch class and name it ContactsCollectionViewLayout. Make sure to have this class inherit from UICollectionViewLayout. The design you are going to implement in your custom layout object is shown in the following screenshot. It looks a lot like a regular horizontally scrolling layout except that the cells are distributed quite playfully, with every other row slightly offset to the right:

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 heavy lifting can be done in the prepare() method. This is where all layout attributes for cells will be calculated, so they are available long before the collection view starts asking for sizes for specific cells that are about to be shown on screen.

The steps required to implement the entire custom layout are the following:

  1. Pre-calculate the layout in the prepare() method.
  2. Implement collectionViewContentSize to provide the collection view with enough information to configure scrolling.
  1. Implement layoutAttributesForElements(in:) to provide layout attributes for items in a certain area.
  2. Implement layoutAttributesForItem(at:) to provide information about the layout of a specific item.
  3. Implement shouldInvalidateLayout(forBoundsChange:) to determine whether a certain change in a collection view's size should trigger a recalculation of the layout.
  4. Assign the custom layout to the collection view.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset