我有一个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];
            }
        }
    }
    

    如果这是一个内部错误,那么这对我来说似乎是一个不错的解决方法,因为它不会更改索引路径的sectionitem值,并且这还意味着您不必继承UICollectionView即可强制其在辞职时进行更新急救人员。

    但是,如果您当前正在compare: -ing或正在测试索引路径上的相等性(例如,使用isEqual:),则此替代方法可能会破坏它。相反,您必须确保仅比较sectionitem来保持相同的功能。

    关于ios - 当键盘可见时,UICollectionView不会重新显示从屏幕上滚动出来的补充 View ,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25189751/

    10-13 04:04