在尺寸更改时使集合视图布局无效的正确方法

时间:2016-05-21 20:52:19

标签: ios uicollectionview uicollectionviewlayout

我实现了一个集合视图,其项目的大小基于集合视图的边界。因此,当大小改变时,例如,由于旋转设备,我需要使布局无效,以便调整单元格的大小以考虑新的集合视图边界。我是通过viewWillTransitionToSize API完成此操作的。

这很有效,直到用户在包含集合视图的视图控制器上呈现模态视图控制器,旋转设备,然后解除它。发生这种情况时,项目大小未更新为适当的大小。调用viewWillTransitionToSize并按预期使布局无效,但集合视图的边界仍然是旧值。例如,当从纵向旋转到横向时,集合视图边界值的高度仍然大于宽度。我不确定为什么会这样,但我想知道这是否是改变尺寸无效的最佳方法?有没有更好的方法呢?

我还尝试了对UICollectionViewFlowLayout进行子类化并覆盖shouldInvalidateLayoutForBoundsChange以返回YES,但由于某些原因,即使没有模态演示也无法轮换。它也没有使用正确的集合视图边界。

- (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
}

我也尝试在完成块中使用它,但它仍然没有使用正确的集合视图边界。

如果我在viewWillAppear中再次使布局无效,则会使用正确的集合视图边界来解决问题,并使用模态显示的视图控制器进行旋转。但这不应该是必要的,也许还有其他情况下,它不能正确调整大小。

1 个答案:

答案 0 :(得分:20)

我知道问题是什么。当您在invalidateLayout内调用animateAlongsideTransition时(在动画块或完成块中),如果在全屏幕上显示模态视图控制器,它实际上不会重新计算布局(但它如果它超过当前的背景,那就会发生。但是如果你像我一样在动画块之外使它无效,它将使它无效。然而,那时集合视图没有为新的大小布局,这解释了为什么我看到它的边界的旧值。此行为的原因是invalidateLayout不会立即导致重新计算布局 - 它计划在下一个布局过程中发生。当全屏显示模态呈现的视图控制器时,不会发生此布局过程。要强制执行布局,只需在[self.collectionView layoutIfNeeded];之后立即调用[self.collectionView.collectionViewLayout invalidateLayout];,仍然在animateAlongsideTransition块内。这将导致按预期重新计算布局。