Implementing shouldInvalidateLayout(forBoundsChange:)

Getting the implementation for shouldInvalidateLayout(forBoundsChange:) is crucial to having a great collection view layout that has amazing performance. If you implement this method incorrectly, you could constantly be invalidating the layout, meaning you will need to recalculate all the time. It's also possible that the collection view will never update its layout at all, even when it should. The collection view will call this method any time its size changes. For instance, when the user rotates their device or when your app runs on an iPad, the user opens another app in multitasking mode.

The layout you have created only need to update when the number of items that fit on the vertical axis changes. The following diagram shows a scenario where invalidating the bounds isn't required because the number of items that fit on the vertical axis does not change:

As you can see, it would not make sense to recalculate the entire layout if the layout of the cells doesn't have to change. The best implementation for this specific layout is to calculate the new number of items on the vertical axis, checking whether this new number is different and then invalidating the layout when it is. Add the following implementation to your layout class:

override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
  guard let collectionView = self.collectionView
    else { return true }

  let availableHeight = newBounds.height - collectionView.contentInset.top - collectionView.contentInset.bottom
  let possibleRows = Int(availableHeight + itemSpacing) / Int(itemSize.height + itemSpacing)

  return possibleRows != numberOfRows
}

This method uses a similar technique as you have seen before to determine the maximum amount of items on the vertical axis. When this new amount is different from the old amount, possibleRows != numberOfRows evaluates to true, and the layout will be invalidated.

This wraps up the work you have to do to set up your layout object; the time has come to see how you can use this custom layout in your project.