旋转后在 UICollectionView 中保留第一个可见项目

Posted

技术标签:

【中文标题】旋转后在 UICollectionView 中保留第一个可见项目【英文标题】:Keep first visible item in UICollectionView after rotation 【发布时间】:2014-10-14 01:51:38 【问题描述】:

我在其他 *** 问题中搜索了答案,但找不到以下问题的任何解决方案:

我正在尝试使用带有流式布局(垂直)的 UICollectionView,并使项目大小取决于屏幕大小(它应该利用 iPad 的宽度,甚至在横向时利用 iPhone 的宽度)。

我想让 UICollectionView 在纵向 iPhone 上只显示一列项目,但在横向 iPhone 上显示 2 列。当然,让它变得通用,这样如果有更多的水平空间可用,它也可以显示更多的列,例如在 iPad 中。

为了实现这种行为,我做了以下操作:

- (void)viewWillLayoutSubviews 

    [super viewWillLayoutSubviews];

    UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout;
    NSInteger columns = 1 + ((NSInteger)(CGRectGetWidth(self.collectionView.frame) - layout.sectionInset.left - layout.sectionInset.right + layout.minimumInteritemSpacing)) / ((NSInteger)(layout.minimumInteritemSpacing + 300.0 + 1.0));
    layout.itemSize = CGSizeMake((CGRectGetWidth(self.collectionView.frame) - layout.sectionInset.left - layout.sectionInset.right - ((columns - 1) * layout.minimumInteritemSpacing)) / columns, layout.itemSize.height);

    [layout invalidateLayout];
 

这很好用,当我旋转手机时,我可以看到布局显示两列而不是一列。

但我无法让 UICollectionView 在旋转后保留第一个可见项目,因为它将内容偏移设置为旋转之前的任何内容。随着布局的改变,现在 UICollectionView 在横向上显示两列,这个新的内容偏移应该有一个新值,它对应于同一个项目,但在一个新的布局下。

我尝试使用以下 sn-p,但没有成功:

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration 

    NSIndexPath *firstAddShowCellIndexPath = [[[self.collectionView indexPathsForVisibleItems] sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) 
        NSIndexPath *ip1 = obj1;
        NSIndexPath *ip2 = obj2;
        return [ip1 compare:ip2];
    ] firstObject];

    if (firstAddShowCellIndexPath) 
        [self.collectionView scrollToItemAtIndexPath:firstAddShowCellIndexPath atScrollPosition:UICollectionViewScrollPositionTop animated:YES];
    

我怀疑 UICollectionView 正在尝试处理旋转期间的内容偏移,所以我什至尝试使用 dispatch_afterwillRotateToInterfaceOrientation,但虽然它确实有效,但它在旋转完成后将内容偏移设置为延迟,给出非常糟糕的用户体验。

有什么想法吗?

谢谢大家!

【问题讨论】:

【参考方案1】:

这对我有用,

添加此方法而不是 willRotation 方法

#pragma mark - Rotation
-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator

    [self.collectionView.collectionViewLayout invalidateLayout];

作为一个例子,这是我在旋转前后制作两个列的快速代码,等等

#pragma mark <UICollectionViewDelegateFlowLayout>
- (CGSize)collectionView:(UICollectionView *)collectionView layout(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath*)indexPath

    int width = roundf(self.collectionView.frame.size.width / 2.0) - 15;
    int height = roundf(width * 0.8);
    return CGSizeMake(width, height);


- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section

    UIEdgeInsets new = UIEdgeInsetsMake(10, 10, 10, 10);
    return new;

【讨论】:

以上是关于旋转后在 UICollectionView 中保留第一个可见项目的主要内容,如果未能解决你的问题,请参考以下文章

UICollectionView 在 reloadData 后在屏幕外崩溃时崩溃

UICollectionView 在旋转时重新排列单元格

屏幕旋转后如何在 UICollectionView 中跟踪单元格的移动

旋转后在 3D 世界中翻译的正确方法?

设备旋转后的 UICollectionView contentOffset

设备旋转时如何自动调整 UICollectionView 的大小?