UICollectionView Invalidate Layout On Bounds Changes

This approach allows you do it without subclassing the layout, instead you add it to your, presumably already existing UICollectionViewController subclass, and avoids the potential of recursively calling viewWillLayoutSubviews it is a variation of the accepted solution, slightly simplified in that it does not use the transitionCoordinator. In Swift:

override func viewWillTransition(
    to size: CGSize,
    with coordinator: UIViewControllerTransitionCoordinator
) {
    super.viewWillTransition(to: size, with: coordinator)
    collectionViewLayout.invalidateLayout()
}

The solution for invalidating your layout when the bounds of the collection view changes is to override shouldInvalidateLayoutForBoundsChange: and return YES. It's also stated in the documentation: https://developer.apple.com/documentation/uikit/uicollectionviewlayout/1617781-shouldinvalidatelayoutforboundsc

- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds 
{
     return YES;
}

This should cover rotation support as well. If it doesn't, implement viewWillTransitionToSize:withTransitionCoordinator:

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
    [super viewWillTransitionToSize:size
          withTransitionCoordinator:coordinator];

    [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context)
     {
         [self.collectionView.collectionViewLayout invalidateLayout];
     }
                                 completion:^(id<UIViewControllerTransitionCoordinatorContext> context)
     {
     }];
}

  1. You should handle the case when the collection view size is changed. If you change the orientation or constraints, viewWillLayoutSubviews method will be triggered.

  2. You should invalidate the current collection view layout. After the layout is invalidated by using invalidateLayout method, the UICollectionViewDelegateFlowLayout methods will be triggered.

Here's the example code:

- (void)viewWillLayoutSubviews {
    [super viewWillLayoutSubviews];
    [mainCollectionView.collectionViewLayout invalidateLayout];
}