使用 invalidateLayout 加载数据后调整 UICollectionViewCell 的大小 [英] Resizing UICollectionViewCell After Data Is Loaded Using invalidateLayout
问题描述
这个问题已经被问过几次了,但没有一个答案足够详细,让我理解为什么/如何工作.作为参考,其他 SO 问题是:
This question has been asked a few times but none of the answers are detailed enough for me to understand why/how things work. For reference the other SO questions are:
如何更新设置单元格数据后UICollectionView中单元格的大小?
设置数据后调整 UICollectionView 单元格的大小一个>
在哪里确定动态大小的高度UICollectionViewCell?
我正在使用 MVC,但为了简单起见,假设我有一个 ViewController,它在 ViewWillAppear 中调用 Web 服务来加载一些数据.数据加载完毕后调用
I'm using MVC but to keep things simple lets say that I have a ViewController that in ViewWillAppear calls a web service to load some data. When the data has been loaded it calls
[self.collectionView reloadData]
self.collectionView 包含 1 个 UICollectionViewCell(我们称之为 DetailsCollectionViewCell).
The self.collectionView contains 1 UICollectionViewCell (let's call it DetailsCollectionViewCell).
创建 self.collectionView 时,它首先调用 sizeForItemAtIndexPath,然后调用 cellForItemAtIndexPath.这给我带来了一个问题,因为只有在 cellForItemAtIndexPath 期间,我才通过以下方式将 Web 服务的结果设置为 DetailsCollectionViewCell:
When self.collectionView is being created it first calls sizeForItemAtIndexPath and then cellForItemAtIndexPath. This causes a problem for me because it's only during cellForItemAtIndexPath that I set the result of the web service to DetailsCollectionViewCell via:
cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"detailsCell" forIndexPath:indexPath];
((DetailsCollectionViewCell*)cell).details = result;
DetailsCollectionViewCell 有一个属性详细信息的设置器,它执行一些工作,我需要首先知道正确的单元格大小应该是多少.
DetailsCollectionViewCell has a setter for the property details that does some work that I need to happen first to know what the correct cell size should be.
根据上面链接的问题,似乎在 cellForItemAtIndexPath 之后调用 sizeForItemAtIndexPath 的唯一方法是调用
Based on the linked questions above it seems like the only way to fire sizeForItemAtIndexPath after cellForItemAtIndexPath is to call
[self.collectionView.collectionViewLayout invalidateLayout];
但这在其他问题对我不起作用的地方,因为虽然它调用 sizeForItemAtIndexPath 并允许我从 DetailsCollectionViewCell 获取足够的信息以设置正确的高度,但它不会更新 UI,直到用户滚动 UICollectionView 和我的猜测它与文档中的这一行有关
But this where the other questions don't work for me because although it calls sizeForItemAtIndexPath and allows me to grab enough information from DetailsCollectionViewCell to set the correct height it doesn't update the UI until after the user scrolls the UICollectionView and my guess is that it has something to do with this line from the documentation
实际的布局更新发生在下一个视图布局更新周期.
The actual layout update occurs during the next view layout update cycle.
但是,我对如何解决这个问题感到困惑.感觉就像我需要在 DetailsCollectionViewCell 上创建一个静态方法,我可以在第一次 sizeForItemAtIndexPath 传递期间将 Web 服务结果传递给它,然后只缓存该结果.但我希望有一个简单的解决方案来让 UI 自动更新.
However, i'm stumped on how to get around this. It almost feels like I need to create a static method on DetailsCollectionViewCell that I can pass the web service result to during the first sizeForItemAtIndexPath pass and then just cache that result. But i'm hoping there is a simple solution to having the UI automatically update instead.
谢谢,
附言- 第一个问题所以希望我正确地遵循了所有规则.
p.s. - First SO question so hope i followed all the rules correctly.
推荐答案
实际上,根据我的发现,调用 invalidateLayout 会导致在下一个单元格出列时为所有单元格调用 sizeForItemAtIndexPath(这是针对 iOS < 8.0,因为 8.0 它将在下一次视图布局更新时重新计算布局).
Actually, from what I found, calling to invalidateLayout will cause calling sizeForItemAtIndexPath for all cells when dequeuing next cell (this is for iOS < 8.0, since 8.0 it will recalculate layout in next view layout update).
所以我想出的解决方案是子类化 UICollectionView,并用这样的东西覆盖 layoutSubviews:
So the solution i came up with, is subclassing UICollectionView, and overriding layoutSubviews with something like this:
- (void)layoutSubviews
{
if ( self.shouldInvalidateCollectionViewLayout ) {
[self.collectionViewLayout invalidateLayout];
self.shouldInvalidateCollectionViewLayout = NO;
} else {
[super layoutSubviews];
}
}
然后在 cellForItemAtIndexPath
中调用 setNeedsLayout
并将 shouldInvalidateCollectionViewLayout
设置为 YES.这在 iOS >= 7.0 中对我有用.我也以这种方式实现了估计的项目大小.谢谢.
and then calling setNeedsLayout
in cellForItemAtIndexPath
and setting shouldInvalidateCollectionViewLayout
to YES. This worked for me in iOS >= 7.0. I also implemented estimated items size this way. Thx.
这篇关于使用 invalidateLayout 加载数据后调整 UICollectionViewCell 的大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!