如何在 self-sizing 发生之前准确地为 UICollectionViewLayout 提供矩形中的元素?

How do I accurately provide elements in a rect for UICollectionViewLayout before self-sizing has occurred?

我正在使用 UICollectionView 构建可以在网格或垂直列表布局中显示元素的 UI。 UICollectionViewFlowLayout 不适合 full-width 列表布局,所以我正在编写自己的 UICollectionViewLayout 子类。并且行是self-sizing,这样它们就可以有多行标签,并且它们的字体大小与系统字体大小设置匹配,并且根据需要grow/shrink

在内部,它具有所有行的 collection 布局属性。在 prepareLayoutprepare in Swift)中,我遍历数据源中的所有索引路径,并创建布局属性,并将其框架设置为估计的行高。

shouldInvalidateLayoutForPreferredLayoutAttributes 中,我 return YES 如果高度与我在 collection 中为该行设置的值不同。然后在 invalidationContextForPreferredLayoutAttributes 中,我使 passed-in preferredAttributes 的索引路径之后的所有项目无效,因为该行中的高度变化会影响所有后续行的垂直位置。然后 prepareLayout 再次被调用,我根据需要更新所有内容的框架。

问题来自于这一系列事件:

如果总行收缩足够大,则不在 layoutAttributesForElementsInRect 的矩形内的一两行会向上移动到足以让它们出现的程度。例如,如果 rect 的 y 值为 0 到 1334,则在调用 shouldInvalidateLayoutForPreferredLayoutAttributes 之前 y 原点为 1340 的行现在可能为 1300。但是布局 object 已经“知道”应该使用哪些行显示在屏幕上,所以这些行不会显示,而且我的列表中有漏洞。

我可以通过 return 从 layoutAttributesForElementsInRect 添加额外的行来解决这个问题(通过将我得到的矩形垂直扩展 100 点或其他)。但那是一个 hack,这似乎是 APIs 应该有办法解决的问题。但是在 self-sizing 完成后我没有再接到 layoutAttributesForElementsInRect 的电话,而且我没有看到通过 UICollectionViewLayoutInvalidationContext.[=31= 要求再次调用它的方法]

那么...我是否遗漏了 API 中明显的内容?这是一个不应该发生的问题,这意味着我正在处理错误的事情吗?似乎没有办法在 self-sizing 发生之前准确回答 layoutAttributesForElementsInRect...?

说明问题的示例代码是 GitHub 上的 here

我发现当您有自调整大小的补充视图时,在 invalidationContextForPreferredLayoutAttributes 中有额外的无效会导致出现布局间隙的错误。我犯了同样的错误,其他人也犯了同样的错误,因为使下面的项目和自我调整大小的项目无效似乎是合乎逻辑的。我的猜测是集合视图会为您处理此问题。

要在您的示例项目中删除的这些 are the lines

[result invalidateItemsAtIndexPaths:rowPaths];
[result invalidateSupplementaryElementsOfKind:UICollectionElementKindSectionHeader atIndexPaths:headerPaths];

我已就此向 Apple 提交文档更新 Radar。 http://www.openradar.me/35833995

我的问题是我从我的自定义布局返回的布局属性丢失了 zIndex 属性 所以自我调整无法正常工作。