UICollectionView使边界更改上的布局无效

我目前有以下片段用于计算UICollectionViewCells大小:

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

这很有效。 但是,我现在在viewDidLoad添加了一个键盘观察器(它在UICollectionView出现之前触发了它的委托和数据源方法,并从故事板中调整自身大小)。 因此,界限是错误的。 我也想支持轮换。 如果UICollectionView改变大小,处理这两个边缘情况并重新计算大小的好方法是什么?

当集合视图的边界发生变化时,使布局无效的解决方案是覆盖shouldInvalidateLayoutForBoundsChange:并返回YES 。 它也在文档中说明: https : //developer.apple.com/documentation/uikit/uicollectionviewlayout/1617781-shouldinvalidatelayoutforboundsc

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

这也应该包括旋转支持。 如果没有,请实现viewWillTransitionToSize:withTransitionCoordinator:

 - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator { [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; [coordinator animateAlongsideTransition:^(id context) { [self.collectionView.collectionViewLayout invalidateLayout]; } completion:^(id context) { }]; } 
  1. 您应该在更改集合视图大小时处理该情况。 如果更改方向或约束,将触发viewWillLayoutSubviews方法。

  2. 您应该使当前集合视图布局无效。 使用invalidateLayout方法使布局无效后,将触发UICollectionViewDelegateFlowLayout方法。

这是示例代码:

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

这种方法允许你在没有子类化布局的情况下完成它,而是将它添加到你的,可能已经存在的UICollectionViewController子类,并避免递归调用viewWillLayoutSubviews的可能性,它是接受的解决方案的变体,稍微简化,因为它不使用transitionCoordinator 。 在Swift中:

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