我已为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:
内部会发生这种情况:
invalidateLayout
之前。在初始时,self.invalidateEverything
和self.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
和朋友(collectionViewContentSize
和layoutAttributesForElementsInRect:
之后)。
我要么丢失了某些密钥,要么这些API被破坏了。当然,我应该能够有效地在布局的末尾添加一个单元格。我是否应该注意到invalidateDataSourceCounts==YES
并警告我的prepareLayout
实施 - "抱歉,您已被通知,但尚未做任何事情。在我知道该怎么做之后我会再次打电话给你。"
或客户端代码是否应该以某种方式创建我的上下文实例并在调用[collection insertItemsAtIndexPaths: newIndices]
之前配置?但那么客户如何在insertItemsAtIndexPaths:
电话中提出这种情况?客户真的应该接触这个实现细节吗?