The correct way to nullify a collection layout when resizing

I am implementing a collection view whose elements are sized based on the boundaries of the collection view. Therefore, when the size changes, due to the rotation of the device, for example, I need to invalidate the layout so that the cell sizes are changed in order to consider the new boundaries of the collection view. I did this using the viewWillTransitionToSize API.

This works well until the user presents a modal view controller over the view controller that contains the collection view, rotates the device, and then rejects it. However, the item size is not updated to the appropriate size. viewWillTransitionToSize is invoked, and the layout is considered invalid, as expected, but collection view restrictions are still the old value. For example, when you turn from portrait to landscape, the value of the collection viewing restriction still has a height greater than the width. I'm not sure why this is so, but I wonder if this is the best way to invalidate when resizing? Is there a better way to do this?

I also tried to subclass UICollectionViewFlowLayout and override shouldInvalidateLayoutForBoundsChange to return YES , but for some reason this does not work even when rotating without a modal representation. It also does not use an appropriate viewing frame.

 - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(nonnull id<UIViewControllerTransitionCoordinator>)coordinator { [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; [self.collectionView.collectionViewLayout invalidateLayout]; [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> __nonnull context) { [self.collectionView.collectionViewLayout invalidateLayout]; } completion:^(id<UIViewControllerTransitionCoordinatorContext> __nonnull context) { //finished }]; } - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewFlowLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { //collectionView.bounds.size is not always correct here after invalidating layout as explained above } 

I also tried to include it in the completion block, but it still does not use the correct collection view frames.

If I invalidate the layout in viewWillAppear , it uses the correct collection view frames, which fix the rotation issue with the modally presented view controller. But this is not necessary, perhaps there are other situations where this will not be properly appreciated.

+7
ios uicollectionview uicollectionviewlayout
source share
1 answer

I know what the problem is. When you call invalidateLayout inside animateAlongsideTransition (either in the animation block or in the completion block), it does not actually recalculate the layout if there is a modal view controller presented across the screen (but it will, if it is in the current context). But this will invalidate it if you invalidate it outside the animation block, as I did. At that time, however, the presentation of the collection was not set out for a new size, which explains why I saw the old meaning of its borders. The reason for this behavior is invalidateLayout , which does not immediately cause the layout to be recalculated - it should appear during the next layout pass. This layout transition does not occur when the controller view presented in the view mode is displayed in full screen mode. To make skip the layout, just call [self.collectionView layoutIfNeeded]; immediately after [self.collectionView.collectionViewLayout invalidateLayout]; still in animateAlongsideTransition block. This will recalculate the layout as expected.

+14
source share

All Articles