使用 invalidateLayout 加载数据后调整 UICollectionViewCell 的大小 [英] Resizing UICollectionViewCell After Data Is Loaded Using invalidateLayout

查看:29
本文介绍了使用 invalidateLayout 加载数据后调整 UICollectionViewCell 的大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题已经被问过几次了,但没有一个答案足够详细,让我理解为什么/如何工作.作为参考,其他 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆