Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UICollectionView Invalidate Layout On Bounds Changes

I currently have the following snippet for calculating UICollectionViewCells sizes:

- (CGSize)collectionView:(UICollectionView *)mainCollectionView
                  layout:(UICollectionViewLayout *)collectionViewLayout
  sizeForItemAtIndexPath:(NSIndexPath *)atIndexPath
{
    CGSize bounds = mainCollectionView.bounds.size;
    bounds.height /= 4;
    bounds.width /= 4;
    return bounds;
}

This works. However, I'm now adding a keyboard observer in viewDidLoad (which is triggering the the delegate and data source methods for the UICollectionView before it appears and resizes itself from the storyboard). The bounds are thus wrong. I also would like to support rotation. What's a good way of handling these two edge cases and re-calculating the sizes if the UICollectionView changes size?

like image 907
Stussa Avatar asked Mar 13 '15 01:03

Stussa


People also ask

What does invalidateLayout do?

invalidateLayout()Invalidates the current layout and triggers a layout update.

What is Uicollectionview flow layout?

A layout object that organizes items into a grid with optional header and footer views for each section.

What is Collectionviewlayout?

An abstract base class for generating layout information for a collection view.

What is compositional layout in Swift?

A compositional layout is a type of collection view layout. It's designed to be composable, flexible, and fast, letting you build any kind of visual arrangement for your content by combining — or compositing — each smaller component into a full layout.


2 Answers

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)
     {
     }];
}
like image 51
bhr Avatar answered Oct 18 '22 02:10

bhr


  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];
}
like image 12
eXtreme Avatar answered Oct 18 '22 04:10

eXtreme