首页 > 解决方案 > UICollectionViewLayout.layoutAttributesForElementsInRect 的行为

问题描述

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

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

我预计func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell将为已返回的每个索引路径调用数据源方法layoutAttributesForElementsInRect

但是我发现如果我只是返回整个属性集:

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

cellForItemAt仍然只为可见矩形内的属性调用方法。

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

是否可以强制 collectionview 调用cellForItemAt所有返回的属性?

标签: iosobjective-cswiftuicollectionviewuicollectionviewlayout

解决方案


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

布局对象的工作是确定集合视图边界内的单元格、补充视图和装饰视图的放置,并在被询问时将该信息报告给集合视图。

然后继续:

集合视图要求其布局对象在许多不同时间为这些元素提供布局信息。屏幕上出现的每个单元格和视图都使用来自布局对象的信息进行定位。

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

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

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

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


推荐阅读