Zac*_*est 6 cocoa-touch ios uicollectionview
我有一个UICollectionViewLayout子类,它指定细胞周围和部分开始和结束的补充视图.出于这个问题的目的,我创建了一个示例项目,它具有我的布局子类的精简版本.我还创建了一个视频,直观地展示了我即将描述的问题.
示例项目如下所示([0, 1]= section 0item 1):
[0, 0] 类型的"部分"级补充视图 HEYCollectionViewElementKindHeaderA[0, 0] 类型的"项目"级别补充视图 HEYCollectionViewElementKindCellA[0, 0] 此索引路径的单元格.[0, 1] 另一种CellA品种[0, 1] 此索引路径的单元格.在示例项目中,我在HEYCollectionViewLayout课堂上注释了一些额外的标题.如果取消注释它们,您可以看到更多未正确重用的视图.
所有的标题视图都有一个UITextField内部,虽然我能够用a UITextView和我自己的同时重现这个问题,UIView它有一个inputView集合并成为第一响应者.当键盘在CellA [0, 0]元素中的文本字段处于活动状态并且您将其上方的补充视图滚动到屏幕外然后重新打开时,视图不会重新添加到集合视图中.
在我的调查中,我发现UICollectionReusableView子类被放置在重用队列中,并hidden=YES在视图层次结构中显示,正如等待重用时所预期的那样.当键盘未激活时,我重新滚动元素,之前显示的类的同一实例将被重用并显示在屏幕上.
我已经尝试具有UICollectionViewLayout询问每个边界变化的重新布局(通过返回YES来自-shouldInvalidateLayoutForBoundsChange:); 这没有任何效果,元素仍然隐藏起来.
我一直无法在互联网上找到有关此问题的任何其他报告,但我已经在Xcode 5.1.1中的iOS模拟器7.1和运行iOS 7.1.2的iPod Touch上重现了它.
我已经通过可能的解决方法更新了上面的回购:
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (BOOL)resignFirstResponder {
BOOL didResign = [super resignFirstResponder];
if (didResign) {
// This works around http://stackoverflow.com/q/25189751/551420
dispatch_async(dispatch_get_main_queue(), ^{
[self.collectionView performBatchUpdates:^{
} completion:^(BOOL finished) {
}];
});
}
return didResign;
}
Run Code Online (Sandbox Code Playgroud)
我认为这个问题是某种破碎的内部状态,UICollectionView通过在UICollectionViewController第一个响应者辞职时强制更新(因为孩子成为第一响应者)来解决这个问题.
这似乎不是正确的解决方案,所以我不是将其标记为答案,但是如果其他人遇到问题,这就是我目前正在尝试解决它的方式.
在我看来,这绝对是某种与正在崩溃的第一响应者打交道的内部状态。
我发现的一种解决方法是通过添加额外的索引来使每个补充视图的索引路径唯一:
- (void)prepareLayout {
[super prepareLayout];
[self.supplementaryViewAttributes removeAllObjects];
[self.cellAttributes removeAllObjects];
CGFloat minimumY = 0;
for (NSInteger sectionIdx = 0; sectionIdx < self.collectionView.numberOfSections; sectionIdx++) {
NSIndexPath *sectionIndexPath = [NSIndexPath indexPathForItem:0 inSection:sectionIdx];
NSInteger suppViewIdx = 0;
NSIndexPath *suppIndexPath = [sectionIndexPath indexPathByAddingIndex:suppViewIdx];
suppViewIdx++;
[self newAttributesForSupplementaryViewAtIndexPath:suppIndexPath
kind:HEYCollectionViewElementKindHeaderA
height:HEYCollectionViewHeaderHeight
minimumY:&minimumY];
suppIndexPath = [sectionIndexPath indexPathByAddingIndex:suppViewIdx];
suppViewIdx++;
[self newAttributesForSupplementaryViewAtIndexPath:suppIndexPath
kind:HEYCollectionViewElementKindHeaderB
height:HEYCollectionViewHeaderHeight
minimumY:&minimumY];
for (NSInteger itemIdx = 0; itemIdx < [self.collectionView numberOfItemsInSection:sectionIdx]; itemIdx++) {
NSIndexPath *itemIndexPath = [NSIndexPath indexPathForItem:itemIdx inSection:sectionIdx];
suppIndexPath = [itemIndexPath indexPathByAddingIndex:suppViewIdx];
suppViewIdx++;
[self newAttributesForSupplementaryViewAtIndexPath:suppIndexPath
kind:HEYCollectionViewElementKindCellA
height:HEYCollectionViewCellHeight
minimumY:&minimumY];
suppIndexPath = [itemIndexPath indexPathByAddingIndex:suppViewIdx];
suppViewIdx++;
[self newAttributesForSupplementaryViewAtIndexPath:suppIndexPath
kind:HEYCollectionViewElementKindCellB
height:HEYCollectionViewCellHeight
minimumY:&minimumY];
[self newAttributesForCellAtIndexPath:itemIndexPath minimumY:&minimumY];
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果这是一个内部错误,那么这对我来说似乎是一个不错的解决方法,因为它不会改变您的索引路径section或item值,并且这也意味着您不必子类化UICollectionView以在它放弃第一响应者时强制它更新。
但是,如果您当前正在compare:索引路径上的相等性(isEqual:例如使用),那么此解决方法可能会打破这一点。相反,您必须确保仅比较section并item保持相同的功能。