UICollectionViewLayout.layoutAttributesForElementsInRect 的行为

Behavior of UICollectionViewLayout.layoutAttributesForElementsInRect

我已经实现了我自己的从 UICollectionViewLayout 子类化的集合视图布局。在 prepare 中,我计算并缓存布局属性。 在 layoutAttributesForElementsInRect 中,我过滤掉那些不正确的:

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    return itemAttributesCache.filter { [=11=].frame.intersects(rect) }
}

我预计数据源方法 func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 将针对 return 在 layoutAttributesForElementsInRect

中编辑的每个索引路径调用

但是我发现如果我 return 整个属性集都是这样的:

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    return itemAttributesCache
}

cellForItemAt 方法仍仅针对可见矩形内的属性调用。

这是预期的行为吗?如果是的话,在我的代码中过滤属性的目的是什么,如果集合视图本身呢?我没有发现任何性能问题。

是否可以强制 collectionview 为所有 returned 属性调用 cellForItemAt

是的,这是集合视图的预期行为。在 UICollectionViewLayout 的文档中,Apple 说(强调):

The job of a layout object is to determine the placement of cells, supplementary views, and decoration views inside the collection view’s bounds and to report that information to the collection view when asked.

然后继续:

The collection view asks its layout object to provide layout information for these elements at many different times. Every cell and view that appears on screen is positioned using information from the layout object.

代码中过滤属性的目的是提高性能。主要有三个因素会影响布局对象的性能:

  • 集合视图数据源中的项数。
  • 确定布局属性的复杂性。
  • 您的自定义布局属性需要的内存量。

在上述条件不友好的情况下(你有很多物品,计算属性很复杂,你的自定义属性需要大量内存)提前计算所有属性不会是可行的,因为预先计算这些值会花费大量时间和资源,因此与其将它们缓存在 prepare 函数中,不如在 layoutAttributesForElementsInRect 中实现一些逻辑来计算布局属性。在这种情况下,您可以使用 visible rect 参数来仅计算将在屏幕上可见的单元格和视图的属性值。

关于强制集合视图为所有返回的属性调用 cellForItemAt,我不确定这样做的价值是什么,因为它只会使用其中的几个。实现这一目标的唯一方法是让集合视图显示您正在显示的内容的大小,以便所有单元格都被视为可见。但是,这样做会使首先使用集合视图的点无效,因为单元格不会被重用,也不会滚动。如果您试图用集合视图项修复一些奇怪的动画,这不是要走的路。