如何在发生自动调整大小之前为UICollectionViewLayout的rect中准确提供元素? [英] How do I accurately provide elements in a rect for UICollectionViewLayout before self-sizing has occurred?
问题描述
我正在使用UICollectionView
构建可以显示网格或垂直列表布局中的元素的UI. UICollectionViewFlowLayout
在全角列表布局中不能很好地发挥作用,因此我正在编写自己的UICollectionViewLayout
子类.并且这些行是自动调整大小的,因此它们可以具有多行标签,并使它们的字体大小与系统字体大小设置匹配,并根据需要增大/缩小
I'm using UICollectionView
to build UI that can display elements in a grid or a vertical list layout. UICollectionViewFlowLayout
doesn't play well with a full-width list layout, so I'm writing my own UICollectionViewLayout
subclass. And the rows are self-sizing, so that they can have multiline labels and match their font size to the system font size setting and grow/shrink as needed
在内部,它具有所有行的布局属性的集合.在prepareLayout
中,我遍历了数据源中的所有索引路径,并使用其框架设置为估计的行高来创建布局属性.
Internally, it has a collection of layout attributes for all rows. In prepareLayout
I walk over all index paths in the data source and create layout attributes with their frames set for an estimated row height.
在shouldInvalidateLayoutForPreferredLayoutAttributes
中,如果高度与集合中该行的值不同,则返回YES
.然后在invalidationContextForPreferredLayoutAttributes
中,我使传入的preferredAttributes
的索引路径之后的所有项目无效,因为此行中的高度变化会影响所有后续行的垂直位置.然后prepareLayout
再次被调用,我会根据需要更新所有内容的框架.
In shouldInvalidateLayoutForPreferredLayoutAttributes
, I return YES
if the height is different than the value I have for that row in my collection. Then in invalidationContextForPreferredLayoutAttributes
, I invalidate all items after the index path of the passed-in preferredAttributes
, because a height change in this row affects the vertical position of all subsequent rows. Then prepareLayout
gets called again and I update the frames of everything as necessary.
问题来自以下一系列事件:
The problem comes with this sequence of events:
-
layoutAttributesForElementsInRect
被调用.我遍历所有属性并检查是否CGRectIntersectsRect(attr.frame, rect)
. -
shouldInvalidateLayoutForPreferredLayoutAttributes
对于即将出现的每一行都会被调用.其中一些最终比原来的估计高度小.
layoutAttributesForElementsInRect
gets called. I walk over all my attributes and check ifCGRectIntersectsRect(attr.frame, rect)
.shouldInvalidateLayoutForPreferredLayoutAttributes
gets called for each row that is about to appear. Some of them end up smaller than the estimated height they had originally.
如果行的总收缩量足够大,则layoutAttributesForElementsInRect
的区域中不存在的一两行将向上移动,足以显示出来.例如,如果rect是y值0到1334,则在shouldInvalidateLayoutForPreferredLayoutAttributes
调用之前的y源为1340的行现在可以在1300.但是布局对象已经知道"应该在屏幕上显示哪些行,因此只是没有显示行,而且我的列表中有孔.
If the total row shrinkage is enough, a row or two that weren't within the rect for layoutAttributesForElementsInRect
get moved up enough that they should appear. For example, if the rect was y values 0 through 1334, a row with y origin 1340 before the calls to shouldInvalidateLayoutForPreferredLayoutAttributes
could now be at 1300. But the layout object already "knows" what rows are supposed to be onscreen, so those rows just don't show up, and there are holes in my list.
我也许可以通过从layoutAttributesForElementsInRect
返回额外的行来解决此问题(通过将rect垂直扩展100点之类的东西).但这是一个hack,这似乎是API应该解决的问题.但是,在自动调整大小之后,我没有再接到layoutAttributesForElementsInRect
的另一个呼叫,而且我也看不到要求通过UICollectionViewLayoutInvalidationContext
再次调用它的方法.
I might be able to work around this by returning extra rows from layoutAttributesForElementsInRect
(by expanding the rect I get by 100 points vertically or something). But that's a hack, and this seems like something that the APIs should have a way to address. But I don't get another call to layoutAttributesForElementsInRect
after self-sizing is done, and I don't see a way to ask for it to be called again via UICollectionViewLayoutInvalidationContext
.
那么...我在API中缺少明显的东西吗?这是不应该发生的问题,这意味着我正在处理错误的东西吗?似乎没有办法在自动调整大小之前准确地回答layoutAttributesForElementsInRect
...?
So...am I missing something obvious in the API? Is this a problem that shouldn't be happening, which means I'm approaching something wrong? It seems like there's no way to accurately answer layoutAttributesForElementsInRect
before self-sizing has happened...?
说明问题的示例代码是此处在GitHub上.
Example code illustrating the problem is here on GitHub.
推荐答案
我发现,当您具有自动调整大小的补充视图时,在invalidationContextForPreferredLayoutAttributes
中具有额外的无效性将导致在布局上存在空白的错误.我犯了同样的错误,其他人也犯了同样的错误,因为使下面的项目无效且自调整大小似乎是合乎逻辑的.我的猜测是,集合视图可以为您解决这个问题.
I've discovered that having extra invalidations in invalidationContextForPreferredLayoutAttributes
when you have self-sizing supplementary views will cause a bug where you get layout gaps. I've made the same mistake and others have too because it seems logical to invalidate the items below and item being self-sized. My guess is that the collection view handles this for you.
这些是这些行在示例项目中删除:
These are the lines to remove in your sample project:
[result invalidateItemsAtIndexPaths:rowPaths];
[result invalidateSupplementaryElementsOfKind:UICollectionElementKindSectionHeader atIndexPaths:headerPaths];
我已就此向Apple提交了文档更新Radar. http://www.openradar.me/35833995
I've filed a documentation update Radar with Apple about this. http://www.openradar.me/35833995
这篇关于如何在发生自动调整大小之前为UICollectionViewLayout的rect中准确提供元素?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!