使用 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 动画
带有 invalidateSupplementaryElements 和 UICollectionViewLayoutInvalidationContext 的 invalidateLayout