使用 invalidateLayout 加载数据后调整 UICollectionViewCell 的大小

Posted

技术标签:

【中文标题】使用 invalidateLayout 加载数据后调整 UICollectionViewCell 的大小【英文标题】:Resizing UICollectionViewCell After Data Is Loaded Using invalidateLayout 【发布时间】:2014-05-18 22:45:29 【问题描述】:

这个问题已被问过几次,但没有一个答案足够详细,让我无法理解事情为何/如何运作。作为参考,其他 SO 问题是:

How to update size of cells in UICollectionView after cell data is set?

Resize UICollectionView cells after their data has been set

Where to determine the height of a dynamically sized UICollectionViewCell?

我正在使用 MVC,但为了简单起见,假设我有一个 ViewController,它在 ViewWillAppear 中调用 Web 服务来加载一些数据。加载数据后,它会调用

[self.collectionView reloadData]

self.collectionView 包含 1 个 UICollectionViewCell(我们称之为 DetailsCollectionViewCell)。

创建 self.collectionView 时,它首先调用 sizeForItemAtIndexPath,然后调用 cellForItemAtIndexPath。这给我带来了一个问题,因为只有在 cellForItemAtIndexPath 期间,我通过以下方式将 Web 服务的结果设置为 DetailsCollectionViewCell:

    cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"detailsCell" forIndexPath:indexPath];
    ((DetailsCollectionViewCell*)cell).details = result;

DetailsCollectionViewCell 有一个属性详细信息的设置器,它执行一些工作,我首先需要知道正确的单元格大小应该是多少。

根据上面的链接问题,似乎在 cellForItemAtIndexPath 之后触发 sizeForItemAtIndexPath 的唯一方法是调用

[self.collectionView.collectionViewLayout invalidateLayout];

但这其他问题对我不起作用,因为虽然它调用 sizeForItemAtIndexPath 并允许我从 DetailsCollectionViewCell 获取足够的信息来设置正确的高度,但它不会更新 UI,直到用户滚动 UICollectionView 和我的猜测是它与文档中的这一行有关

实际的布局更新发生在下一个视图布局更新周期。

但是,我不知道如何解决这个问题。感觉就像我需要在 DetailsCollectionViewCell 上创建一个静态方法,我可以在第一次 sizeForItemAtIndexPath 传递期间将 Web 服务结果传递给它,然后只缓存该结果。但我希望有一个简单的解决方案可以让 UI 自动更新。

谢谢,

附言- 第一个 SO 问题,希望我正确遵守所有规则。

【问题讨论】:

【参考方案1】:

实际上,根据我的发现,调用 invalidateLayout 将导致在下一个单元格出列时为所有单元格调用 sizeForItemAtIndexPath(这是针对 ios

所以我想出的解决方案是子类化 UICollectionView,并用类似这样的东西覆盖 layoutSubviews:

- (void)layoutSubviews

    if ( self.shouldInvalidateCollectionViewLayout ) 
        [self.collectionViewLayout invalidateLayout];
        self.shouldInvalidateCollectionViewLayout = NO;
     else 
        [super layoutSubviews];        
    

然后在cellForItemAtIndexPath 中调用setNeedsLayout 并将shouldInvalidateCollectionViewLayout 设置为YES。这在 iOS >= 7.0 中对我有用。我也以这种方式实现了估计的项目大小。谢谢。

【讨论】:

你能在这里扩展你的答案吗? .shouldInvalidateCollectionViewlayout 不是 UICollectionView 上的属性? 我已经实现了这个,但我的单元格仍然只是在我滚动集合视图后才调整大小。想法?【参考方案2】:

这是我的案例和解决方案。

我的 collectionView 在一个 scrollView 中,我希望我的 collectionView 和她的单元格在我滚动我的 scrollView 时调整大小。

所以在我的 UIScrollView 委托方法中:scrollViewDidScroll:

[super scrollViewDidScroll:scrollView];

if(scrollView.contentOffset.y>0)

    CGRect lc_frame = picturesCollectionView.frame;
    lc_frame.origin.y=scrollView.contentOffset.y/2;
    picturesCollectionView.frame = lc_frame;

else

    CGRect lc_frame = picturesCollectionView.frame;
    lc_frame.origin.y=scrollView.contentOffset.y;
    lc_frame.size.height=(3*(contentScrollView.frame.size.width/4))-scrollView.contentOffset.y;
    picturesCollectionView.frame = lc_frame;

    picturesCollectionViewFlowLayout.itemSize = CGSizeMake(picturesCollectionView.frame.size.width, picturesCollectionView.frame.size.height);
    [picturesCollectionViewFlowLayout invalidateLayout];

我不得不重新设置 collectionViewFlowLayout 单元格大小,然后使他的布局无效。 希望对您有所帮助!

【讨论】:

以上是关于使用 invalidateLayout 加载数据后调整 UICollectionViewCell 的大小的主要内容,如果未能解决你的问题,请参考以下文章

使用 invalidateLayout 调用的高级 UICollectionView 动画

iOS8 中的 invalidateLayout 等效项

带有 invalidateSupplementaryElements 和 UICollectionViewLayoutInvalidationContext 的 invalidateLayout

UICollectionView invalidateLayout 不会在屏幕方向更改时触发 sizeForItem

使用ajax重新加载后jquery数据表格式消失

使用 ajax json 加载数据后,引导数据表无法正常工作