我有一个UICollectionViewLayout
子类,它指定单元格周围以及节的开头和结尾的补充 View 。出于这个问题的目的,我创建了一个sample project,它具有我的布局子类的简化版本。我还创建了a video,以可视方式演示了我将要描述的问题。
该示例项目对此类内容进行了布局([0, 1]
=一部分0
项目1
):
[0, 0]
HEYCollectionViewElementKindHeaderA
类型的“节”级补充 View [0, 0]
HEYCollectionViewElementKindCellA
类型的“item”级补充 View [0, 0]
此索引路径的单元格。 [0, 1]
另一个单元格[0, 1]
此索引路径的单元格。 在示例项目中,我在
HEYCollectionViewLayout
类中注释了一些其他 header 。如果您取消注释,则可能会看到更多未正确重用的 View 。所有 header View 的内部都有一个
UITextField
,尽管我可以用UITextView
和我自己的UIView
(已设置inputView
并成为第一响应者)重现此问题。当键盘在CellA [0, 0]
元素中的文本字段上处于事件状态时,如果您在屏幕外滚动其上方的补充 View ,然后又重新打开,则这些 View 不会重新添加到集合 View 中。在调查中,我发现
UICollectionReusableView
子类放置在重用队列中,并在 View 层次结构中显示为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;
}
我相信问题是
UICollectionView
中某种内部状态损坏,只要UICollectionViewController
辞职第一响应者(因为 child 成为第一响应者),就会通过强制更新来解决此问题。这似乎不是正确的解决方案,因此我没有将其标记为答案,但是如果其他人遇到问题,这就是我目前正在尝试解决的方法。
最佳答案
在我看来,这肯定是某种内部状态,正在处理即将崩溃的第一响应者。
我发现的一种解决方法是,通过添加额外的索引来使每个补充 View 的索引路径唯一:
- (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];
}
}
}
如果这是一个内部错误,那么这对我来说似乎是一个不错的解决方法,因为它不会更改索引路径的
section
或item
值,并且这还意味着您不必继承UICollectionView
即可强制其在辞职时进行更新急救人员。但是,如果您当前正在
compare:
-ing或正在测试索引路径上的相等性(例如,使用isEqual:
),则此替代方法可能会破坏它。相反,您必须确保仅比较section
和item
来保持相同的功能。关于ios - 当键盘可见时,UICollectionView不会重新显示从屏幕上滚动出来的补充 View ,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25189751/