我正在使用 UICollectionView
构建可以在网格或垂直列表布局中显示元素的 UI。 UICollectionViewFlowLayout
不能很好地适应全角列表布局,因此我正在编写自己的 UICollectionViewLayout
子类。并且行是自动调整大小的,因此它们可以具有多行标签,并将其字体大小与系统字体大小设置相匹配,并根据需要增大/缩小
在内部,它具有所有行的布局属性的集合。在 prepareLayout
(Swift 中的 prepare
)中,我遍历数据源中的所有索引路径,并创建布局属性,并将其框架设置为估计行高。
在 shouldInvalidateLayoutForPreferredLayoutAttributes
中,如果高度与集合中该行的值不同,我将返回 YES
。然后,在 invalidationContextForPreferredLayoutAttributes
中,我使传入的 preferredAttributes
的索引路径之后的所有项目无效,因为该行的高度更改会影响所有后续行的垂直位置。然后再次调用 prepareLayout
并根据需要更新所有内容的框架。
问题是由这一系列事件引起的:
layoutAttributesForElementsInRect
被调用。我遍历所有属性并检查是否CGRectIntersectsRect(attr.frame, rect)
。
对于即将出现的每一行都会调用 shouldInvalidateLayoutForPreferredLayoutAttributes
。其中一些最终比最初估计的高度要小。
如果总行收缩足够,则不在 layoutAttributesForElementsInRect
的矩形内的一两行会向上移动到足够的位置,以便它们应该出现。例如,如果矩形的 y 值是 0 到 1334,则在调用 shouldInvalidateLayoutForPreferredLayoutAttributes
之前 y 原点为 1340 的行现在可能位于 1300。但是布局对象已经“知道”应该包含哪些行在屏幕上,所以这些行不会显示,并且我的列表中存在漏洞。
我也许可以通过从 layoutAttributesForElementsInRect
返回额外的行来解决这个问题(通过将我得到的矩形垂直扩展 100 点或其他)。但这是一种黑客行为,API 应该有办法解决这个问题。但在完成自调整大小后,我没有再次调用 layoutAttributesForElementsInRect
,并且我没有找到一种方法来要求通过 UICollectionViewLayoutInvalidationContext
再次调用它。
那么...我是否遗漏了 API 中明显的东西?这是一个不应该发生的问题吗?这意味着我正在处理错误的事情吗?在自调整大小发生之前似乎没有办法准确回答 layoutAttributesForElementsInRect
...?
说明问题的示例代码是 here在 GitHub 上。
最佳答案
我发现,当您具有自调整大小的补充 View 时,在 invalidationContextForPreferredLayoutAttributes
中进行额外的失效会导致出现布局间隙的错误。我犯了同样的错误,其他人也犯了同样的错误,因为使下面的项目无效并且项目自行调整大小似乎是合乎逻辑的。我的猜测是 Collection View 会为您处理这个问题。
这些are the lines要在示例项目中删除:
[result invalidateItemsAtIndexPaths:rowPaths];
[result invalidateSupplementaryElementsOfKind:UICollectionElementKindSectionHeader atIndexPaths:headerPaths];
我已向 Apple 提交了有关此问题的文档更新 Radar。 http://www.openradar.me/35833995
关于objective-c - 在发生自调整大小之前,如何准确地为 UICollectionViewLayout 提供矩形中的元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51389649/