Implementing layoutAttributesForElements(in:)

More complex than collectionViewContentSize is layoutAttributesForElements(in:). This method is responsible for providing a collection view with the layout attributes for several elements at once. The collection view always provides a rectangle, for which it needs layout attributes. The layout is responsible for providing these attributes to the collection view as fast as possible. It is essential that the implementation of this method is as efficient as you can get it to be; your scroll performance depends on it.

Even though there is only a small number of cells visible at a time, the collection view has a lot more content outside of its current viewport. Sometimes it is asked to jump to a particular cell, or the user scrolls extremely fast. There are many cases for the collection view to ask for all layout attributes for several cells at once. When this happens, the layout object can help the cell determine which cells should be visible for a particular rectangle. This is possible because the layout attributes do not only contain the rectangle in which a cell should be rendered, it also knows the IndexPath object that corresponds with that specific cell.

This is pretty complicated matter, and it's okay if you find this to be a little bit confusing. As long as you understand that a collection view can ask its layout which cells are present in a certain CGRect instance and how they should be rendered, you understand what layoutAttributesForElements(in:) does. The most straightforward implementation we can come up with for layoutAttributesForElements(in:) is the following:

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
  return layoutAttributes.filter { attributes in
    return attributes.frame.intersects(rect)
  }
}

This code filters the list of attributes and returns a new list that only contains attributes that are within the bounds of the supplied rectangle. Note that this implementation might not be the best possible implementation for your custom layout. As the number of items in the collection grows, the time to run the filter grows too. You might be better off implementing a different method to look up the correct items. This depends on your exact use case, layout, and bottlenecks.