使用UICollectionViewLayoutInvalidationContext在插入,删除和移动期间优化布局计算

时间:2016-02-25 02:57:17

标签: ios uicollectionview uicollectionviewlayout

我已为UICollectionViewLayout实施了自定义UICollectionView,并且还希望自定义UICollectionViewLayoutInvalidationContext获得良好的效果。

在我的第一个用例中,我有浮动标题,在滚动过程中我只会使需要滑动的标题无效。

我这样做如下:

  • 我从YES返回shouldInvalidateLayoutForBoundsChange:
  • 当我的invalidationContextForBoundsChange:方法被调用时,我通过调用invalidateSupplementaryElementsOfKind:atIndexPaths:向上下文添加过时的标题。
  • invalidateLayoutWithContext:被调用时,我真的不需要做任何事情,因为标题无效就足以让以下关键事情发生layoutAttributesForSupplementaryViewOfKind:atIndexPath:获取而不是用prepareLayout重新开始的一切。

这很有效。

我的第一个问题是:这种情况如何抑制prepareLayout序列?起初我认为向上下文添加任何数据(在这种情况下是陈旧补充的索引路径)足以让Apple认为我知道我在做什么(iOS8明智)而不是调用prepareLayout。我知道更长时间相信你正如下面所见。

我的第二个用例:实际上,我的数据源几乎总是只在最后添加项目。对于我的布局算法,这意味着早期(indexPath-wise)项的布局不会对新数据无效。我不想花时间重新计算我不需要的大量布局属性。所以我需要做" 正确的事情"当客户端代码调用时说:

[collection insertItemsAtIndexPaths: newIndices];

通过注意newIndices中最早的indexPath是什么,并从那里开始重新计算我的布局。几乎总是,newIndices从最后开始,没有现有的单元格过时 - 因此Apple应该只向我的布局对象询问新单元格的属性。

但是请注意,对于插入/删除/移动调用,invalidationContextForBoundsChange:没有类似的方法。所以我没有办法预先配置我的上下文,说明哪些指标来来往往。

因此,在调用insertItemsAtIndexPaths:内部会发生这种情况:

  • 我的上下文对象获取-init' ed。这种情况发生在早期 - 调用invalidateLayout之前。在初始时,self.invalidateEverythingself.invalidateDataSourceCounts是(NO,NO)(并且他们只读取)。
  • 接下来我的invalidateLayoutWithContext:被调用,invalidateDataSourceCounts设置为YES - Apple只告诉我我的计数是陈旧的。这没用,因为它没有告诉我关于在哪里重新开始布局计算的任何事情。但这是我第一次(也是唯一的机会)注意某些事情或做某事。
  • 接下来我的prepareLayout被召唤 - Grrr!我不想重新开始。我不想要prepareLayout被叫 - 或者至少我需要在它被叫之前存储一些信息,所以我不会过度工作。但我唯一的机会是在invalidateLayoutWithContext:,而且在调用时我不知道任何事情(记住没有类似于invalidationContextForBoundsChange:)。进一步invalidateDataSourceCounts==YES没用。

我尝试在invalidateItemsAtIndexPaths:invalidateLayoutWithContext:查看任何旧单元格,以测试是否足以阻止对prepareLayout的调用(如果我以某种方式弄明白哪个细胞到inval)。不行 - prepareLayout仍被召唤。所以第二个问题:invalidateLayoutWithContext:是否为“Apple invalidateItemsAtIndexPaths:这样的问题做出反应太晚了?”

现在为了给伤害添加侮辱,我在调试器中注意到在invalidateLayoutWithContext:时我的上下文有一个名为_updateItems的私有ivar,它具有我需要的所有信息(在我得到的时候)有机会使用它)。但这种伊娃没有吸气剂。只有在调用UICollectionViewUpdateItem方法时才会传递这些prepareForCollectionViewUpdates:条目。但是猜猜这个被调用 - 在prepareLayout和朋友(collectionViewContentSizelayoutAttributesForElementsInRect:之后)。

我要么丢失了某些密钥,要么这些API被破坏了。当然,我应该能够有效地在布局的末尾添加一个单元格。我是否应该注意到invalidateDataSourceCounts==YES并警告我的prepareLayout实施 - "抱歉,您已被通知,但尚未做任何事情。在我知道该怎么做之后我会再次打电话给你。"

客户端代码是否应该以某种方式创建我的上下文实例并在调用[collection insertItemsAtIndexPaths: newIndices]之前配置?但那么客户如何在insertItemsAtIndexPaths:电话中提出这种情况?客户真的应该接触这个实现细节吗?

0 个答案:

没有答案