In the first and the second article, I looked at how to work with UICollectionViewCompositionalLayout and UICollectionViewDiffableDataSource. They are the main components for UICollectionView. But all of this is just a theory, how to use them in practice? How to build a complex layout with them?
This is what I will explain in this article. My solution is not universal, but using it I have handled all the requirements I came up with.
Let’s imagine that we have a library, our goal is to build a mobile app in which library clients can take and return books. In this mobile application we will have three sections:
- Information about a client
- Client books list
- Library books list
In the end, the application will look like at the screenshot
Before starting developing our sections, I need to resolve one problem. From the screenshot, you can see that in different sections we have different objects and they have a different layout. With UICollectionViewDiffableDataSource we can’t do that, that’s why I will build a wrapper and it will help us.
I want to use just structures, this will be a small experiment for me, with them it will be easier to implement a Hashable protocol, but harder to store them.
Section & Cell
For a start let’s create two basic objects for our application. First will be a simple protocol Cell, this protocol will be implemented by our collection view cells. Inside it will have only one function, this function will be called by section and will configure a cell. Also, it will have an associatedtype Object, which will be passed in that function.
Second object is an abstract class Section, it will implement a Hashable protocol and this class helps us to have the common behavior for all future sections.
CollectionAdapter is a class, it will handle our two crucial objects UICollectionViewCompositionalLayout and UICollectionViewDiffableDataSource. This adapter will store UICollectionViewDiffableDataSource and will ask for snapshots data from its delegate. As we decided in sections, we will have different elements, that’s why will use the AnyHashable structure.
The delegate will have two simple methods, the first will return all sections to our collection, second will return elements for the section. Section will provide cells for the data source, that’s why we should add a function to it.
Working with UICollectionViewCompositionalLayout is much more simple, all we have to provide is how elements will layout in the sections. In order to do this, the section must have an additional function that will return this information.
One more important function we must add to our adapter is the one that will create snapshots and send them to the datasource using the apply method. Also before that, it must register cells in a collection. ViewController will be the delegate for our adapter and will return al thel needed data. Below you can find the code for this function.
I have decided that in one section I will have only one kind of elements. With this let me introduce to you a generic section class which I will use for sections — CollectionSection. This class will have two generic elements, first will be our element and second — a cell for it. This class will inherit from the Section class and will return cells and layout for our adapter.
Regarding our requirements in this section we should have short information about the client and amount of books he has taken. So we need a cell and a model.
After this we should configure our new section and return data for it from ViewController to the adapter.
Library Books Section
Next, our section will be the section where we will show books in the library. This section will hold books and if we take one it will have a checkmark on it and also will be added to the client books section.
Cells in it will have dynamic height and grid layout. For taking and returning books we should define one method, this method will be called when we tap on the cell. It should be added to CollectionAdapter, Section, and CollectionSection.
Next step is to implement this method inside ViewController
With this small amount of code we have two sections. And if a client takes some book we will see the change in the client section.
Client Books Section
In this section will be books which client have taken from the library, the section should have horizontal scrolling and if we tap on the return button in the cell, the book should be returned to the library.
Two interesting requirement we should cover here. First, we have to have an empty view which will show that we don’t have any books at a client home. For this requirement I have decided to use the supplementary view, using UICollectionViewCompositionalLayout we can put it inside the section and it will take the whole section size. UICollectionViewCompositionalLayout is pretty smart and will draw the empty view even if it has no elements inside.
I will create a separate section, it will inherit from ClientBooksSection, this section can return a supplementary view for the collection and will show it only if the section doesn’t have elements. Section will know about that from the adapter.
Second, add additional configuration to the cell, it is because ViewController will be the delegate for the cell and react when user taps on the return button, after that a book will be returned to the library.
The bottom line for all three articles is — Apple did what they should have done a long time ago, it gives us instruments that will help in the collection development, this is good, but it is bad that it is a little bit late. As soon as you stop supporting iOS 12 you can do refactoring for your old collections using these new instruments. Full project source code you can find at Github.