我已经为集合视图实现了粘性部分标题,使用 http://blog.radi.ws/post/32905838158/sticky-headers-for-uicollectionview-using 作为起点,它们有效。
但我看到了一个非常奇怪的崩溃。
当我推送编辑器详细信息视图时,更改项目的名称,使其从一个部分移动到另一个部分(想想,更改联系人列表中按姓氏首字母分组的人的姓氏(,然后弹出回集合视图,它崩溃并提出投诉
UICollectionView received layout attributes for a cell with an index path that does not exist
以下是执行流程:
在编辑器详细信息视图中,我更改了项目的名称,使其从部分 X 移动到部分 Y。
物料的模型发出"名称已更改"通知。
拥有集合视图的根视图控制器捕获"名称已更改"通知,重新生成其内部索引,然后在集合视图上调用 -reloadData。这一切都很好。
我点击了 UI 中的"后退"按钮,发生了以程(通过调试器和穴居人 NSlog 调用确认(
- 被调用的节数,我的代码返回正确的节数
- collectionView:NumberOfItemsInSection: 为每个部分调用,并返回正确的项目数
- 我的自定义流布局的 -layoutAttributesForElementsInRect: 被调用。我在那里做的第一件事是调用[super layoutAttributesForElementsInRect]来获取基线布局。
记录继承的基线布局,我看到的是以前单元格排列的属性,而不是当前排列的属性。 例如,布局适用于我刚刚进行的编辑之前的排列。因此,不正确的部分和/或不正确部分中的单元格。
现在这就是让我大吃一惊的地方。
如果我注释掉 -layoutAttributesForElementsInRect 的整个实现,它仍然崩溃。但是,如果我评论掉:
- (BOOL) shouldInvalidateLayoutForBoundsChange:(CGRect)newBound {
return YES;
}
然后,它正常工作。
这告诉我集合视图或流布局中的某些内容正在缓存结果,但前提是流布局应该无效布局边界更改
请注意,如果我只使用香草UICollectionViewFlowLayout,一切正常。
TLDR
自定义 UICollectionViewFlowLayout,如果 -shouldInvalidateLayoutForBoundsChange 返回 YES,则从 [super layoutAttributesForElementsInRect] 获取过期的布局属性
有什么想法吗?
我通过删除shouldInvalidateLayoutForBoundsChange:
覆盖来解决此问题,而是在集合视图的委托上实现scrollViewDidScroll:
以使布局无效:
override func scrollViewDidScroll(scrollView: UIScrollView) {
collectionView?.collectionViewLayout.invalidateLayout()
}
这会保留粘性标头,但会阻止崩溃。