使用缓存的 UICollectionViewLayoutAttributes 子类化 UICollectionViewLayout

Posted

技术标签:

【中文标题】使用缓存的 UICollectionViewLayoutAttributes 子类化 UICollectionViewLayout【英文标题】:Subclassing UICollectionViewLayout with cached UICollectionViewLayoutAttributes 【发布时间】:2019-05-31 22:44:04 【问题描述】:

我正在尝试了解 UICollectionViewLayout 的工作原理并找到此示例代码。

https://developer.apple.com/documentation/uikit/uicollectionview/customizing_collection_view_layouts

在示例代码(以及我能找到的所有其他示例)中,它具有cachedLayoutAttributes 对象并计算prepare() 中所有项目的布局。

我发现此模式有 2 个问题。

一个是如果数据源的数量足够大,在prepare()方法中计算所有东西都需要时间(并且每当collectionView的布局发生变化时都会重新计算),所以看起来效率不高。

另一个问题是layoutAttributesForItemlayoutAttributesForSupplementaryView 没有机会被调用。只有layoutAttributesForElements 被调用,它似乎足以布置单元格/补充视图。

我阅读了文档,但它只说必须覆盖这些方法。我最好的猜测是我应该使用覆盖这些方法来返回适当的UICollectionViewLayoutAttributes 并从layoutAttributesForElements 调用它们。然而,每当用户滚动 UICollectionView 时,都会调用这个 layoutAttributesForElements,所以它似乎也不是很有效。

我想知道layoutAttributesForItemlayoutAttributesForSupplementaryView被调用的情况是什么,如果数据源的数量很大,什么/何时/哪里是计算UICollectionViewLayoutAttributes的最佳方式/地点/时间。

更新

感谢您的评论。然而,它似乎是关于失效周期的优化。

旨在支持失效上下文的布局对象可以使用 UICollectionViewLayoutInvalidationContext 对象中的信息来优化它们在失效周期期间的行为。

这意味着UICollectionViewLayoutAttributes 已经设置并且只有必要的部分无效,对吧?

那么,第一次应该在哪里计算UICollectionViewLayoutAttributes?如果我错了,请告诉我。

【问题讨论】:

阅读 UICollectionViewLayout 文档,尤其是。 “使用无效上下文优化布局性能”部分。还有很多关于这个主题的有用的 WWDC 视频,例如 WWDC 2014 session 226。 同年的第 232 届会议。 @matt 谢谢。我更新了问题。 很明显,一个最小的实现是仅当您收到对矩形中项目布局属性的请求时才执行计算和缓存。这些都是最初需要出现在屏幕上的所有项目。但是,您必须执行 一些 整体初始计算,因为第一个大问题是内容视图需要多大。 【参考方案1】:

一个是如果数据源的数量足够大,在prepare()方法中计算所有东西都需要时间(并且每当collectionView的布局发生变化时都会重新计算),所以看起来效率不高。

是的,它看起来效率不高。让prepare() 的计算尽可能高效是您的工作。

例如:只计算一部分属性,当滚动使用shouldInvalidateLayout(forBoundsChange:)改变它的位置时计算更多。但是要小心这种方法,因为它可能会使每个像素滚动上的布局无效。

prepare() 方法不是为了好玩而调用的,它会通知您某些内容已更改并且需要重新计算!但是很难获得有关变化的信息。您可以在准备之前查看IGListKit 如何获取有关更改的信息:link。

另一个问题是layoutAttributesForItemlayoutAttributesForSupplementaryView 没有机会被调用。只有layoutAttributesForElements 被调用,它似乎足以布置单元格/补充视图。

layoutAttributesForElements(in:) 首先被调用,因为该集合不知道您的单元格和补充视图的顺序。所以它要求指定矩形中的所有属性。尝试插入/移动/删除/重新加载单元格,我相信可能会调用layoutAttributesForItem(at:)。或者可能不是。但是您不必担心,因为您已经拥有属性缓存。

既然你缓存了属性 layoutAttributesForElements(in:) 应该足够高效并且看起来像这样:

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? 
    return attributes
        .reduce(into: [UICollectionViewLayoutAttributes](),  $0 += $1.filter( $0.frame.intersects(rect) ) )

我个人建议查看一些困难的开源布局。与来自任何简单示例项目的信息相比,您将获得更多关于 UICollectionViewLayout 的信息。

【讨论】:

以上是关于使用缓存的 UICollectionViewLayoutAttributes 子类化 UICollectionViewLayout的主要内容,如果未能解决你的问题,请参考以下文章

php 中如何使用缓存,使用哪种缓存机制最好;

RedisRedis 的缓存使用技巧(商户查询缓存)

RedisRedis 的缓存使用技巧(商户查询缓存)

RedisRedis 的缓存使用技巧(商户查询缓存)

如何使用yii2的缓存依赖特性

Mybatis缓存的使用和源码分析