Create your own UICollectionView API

Gwenn Guihal
6 min readMar 5, 2019

--

In this article, we will create an external framework that will expose some cells, a background and horizontal line decorationViews and one vertical custom UICollectionViewFlowLayout that manages margins and paddings between cells.

The app and it’s debug view

Why using UICollectionview ?

According to your app, using UICollectionView to build your screens could save you a lot of time, mostly if your screens are data-oriented and contextual.
It’s easier to add a cell between two others than updating constraints to show or hide an UI element.

A powerful feature of UICollectionView is DecorationView. Without adding complexity on your cells, you can add backgrounds behind some of them and reuse them in the whole app.

Finally, UICollectionView allows to animate changes in your screens with just a few lines of code.

oui.sncf — quote screens made with Collor

Why an API ?

Most of the time, app screens are designed with the same design: same buttons, same elements in many screens with just different contents but same layout.

The purpose to create an API is to use these elements in the simplest way. The main goal of an UICollectionView API is to spend less time on building screens and to spend more time to implement and test the logic, improve details and have a more maintainable code.

Another advantage is to provide an overall UI consistency in the app and to create screens as closely as possible to the mockups given by your(s) designer(s).

Collor

The API provided by Apple for implementing UICollectionView is indexPath-oriented. At oui.sncf, we created an over-layer, called Collor, to have a data-oriented implementation. The main goal of this library is to describe, in one file, the structure of your UICollectionView.

DataSource of RealTime sample app

Before continuing reading this article, you should take a look at these two articles:

Let’s go

1) Creating your own framework

For optimising compilation time and minimising dependencies, the best way is to create a framework in your workspace. We name it CollorAPI. If you project to use this framework in others projects, I suggest you to create a private pod.

We don’t explain the process of creating a framework here, you can find a lot of tutorials if you need one:

2) An unique section descriptor

Most of the time, an unique customisable section descriptor is sufficient for our need.

SectionDescriptor

The second class we create in our new framework is a subclass of CollectionData inside of which we add a method to instantiate the section descriptor created just before:

CollectionData super class

Right now, we can add sections easily:

Sample CollectionData

3) The builder

Next step it’s the creation of the builder! It’s the object that will expose methods in order to facilitate the life of your team. For now, the builder exposes two functions to add a custom descriptors and a LabelCell:

Implementation of the builder

Instead of passing as parameter an array of cells in the closure used to build a section, we pass the builder, then we save the informations owned by the builder in the section descriptor. Pretty simple ;)

Implementation of the builder in the SectionDescriptor

Ok, it’s cool, our API becomes useful: for each type of generic cell (which is used at least twice in the project), the builder exposes a method to create one easily and it indexes all of these. At oui.sncf, we created more than 50 reusable cells and it’s not over yet.

List of generic cells in oui.sncf app

4) Vertical spaces

Each generic cell must be designed edge-to-edge. Then margin and padding will be handle in the layout of the collectionView and with section insets. By applying this rule, it is easier to respect design screens without adding complexity in the cell or adding empty cells to fill in the gaps.

edge-to-edge cells

First, we implement this feature in the builder:

Vertical spaces in the builder

Each time we need to add spaces between two cells, we just call builder.add(verticalSpace: .huge). This sample is simplified: It’s impossible to add spaces more than once and to add space at the beginning of a section (before the first cell). You can do that later, according to your need.

Spaces are stored in a dictionary, this dictionary is passed to the section then used in our custom layout:

VerticalSpaces in the SectionDescriptor
Custom UICollectionViewFlowLayout with verticalSpaces

Each time there is a verticalSpace, the globalOffset is incremented then the next cell origin is offset by this value. The content size is also offset by this value. With this code, you can now add spaces between cells with an elegant way and without dirty tricks :) Don’t forget to set the the custom layout as layout of the collectionView.

5) Decorations

The goal of decorationViews is to add some graphic parts behind cells but without altering them. In CollorAPI a decoration is represented by a decorationBlock. A decoration view needs an origin and a size: the origin is defined with the origin of the the first cell and the size is computed by the right bottom corner of the last cell (in a vertical layout). To get these informations, the decoration stores some properties:

  • the sectionDescriptor (for retrieving section index and some other informations)
  • startItemIndex and endItemIndex (for computing indexPaths and retrieves cell attributes in the layout)
  • type: the decorationView type
DecorationBlock

Now, we just have to add this feature on our builder with two new methods:

  • startDecorationBlock(:): get the current index of the section and begins a decorationBlock.
  • endDecorationBlock(:): get the current index of the section and ends the decorationBlock.
DecorationBlock in the Builder

VerticalCollectionViewLayout is updated to handle decorationBlocks:
We loop on all decorationBlocks then, according to the type, decorationViews are created using layoutAttributes of cells computed just before with verticalSpaces.
Each time you need a new kind of decorationView, you just have to add a new entry in the enum DecorationBlockType and update the layout to handle it.

Custom UICollectionFlowLayout with decorationBlocks
.whiteBordered decorationView result

Finally, the collectionData looks like this:

CollectionData with blocks and spaces

You can download sources of the sample on github (SampleCollorAPI branch). In this example, there is another type of DecorationBlockType: .horizontalLine. As its name suggests, it enables to add horizontal line between cells. You are free to improve the code for even more flexibility.

6) To go further

At oui.sncf, there are 11 decoration types. They enable to add a ticket background or build a journey timeline. For the timeline we created a nested builder inside the section builder. By this way, roles are well separated and the API remains simple to use by other developers. Cells are are shifted to the right in the layout in order to reuse them instead of creating new ones with inside offset.

timeLineBuilder

To resume, in this article we went through the bases of your future framework. It is now up to you to make it evolve according to your needs!

Thanks for reading, and let me know what you think on Twitter.

--

--

Gwenn Guihal

Lead iOS developer at oui.sncf, Paris / Indie game developer (cocos2d-X). Creator of YesSir and Troisix.