当键盘可见时,UICollectionView不会重新显示在屏幕上滚动的补充视图

时间:2014-08-07 18:38:34

标签: ios cocoa-touch uicollectionview

我有一个UICollectionViewLayout子类,它指定了单元格周围和部分开头和结尾的补充视图。出于这个问题的目的,我创建了一个sample project,其中包含了我的布局子类的精炼版本。我还创建了a video,它直观地展示了我将要描述的问题。

示例项目如下所示([0, 1] = section 0 item 1):

  • [0, 0]类型HEYCollectionViewElementKindHeaderA
  • 的“部分”级补充视图
  • [0, 0]类型HEYCollectionViewElementKindCellA
  • 的“项目”级别补充视图
  • [0, 0]此索引路径的单元格。
  • [0, 1]另一种CellA品种
  • [0, 1]此索引路径的单元格。

在示例项目中,我在HEYCollectionViewLayout类中注释了一些其他标题。如果取消注释它们,您可以看到更多未正确重用的视图。

所有标题视图中都有一个UITextField,但我能够使用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;
}

我认为问题是UICollectionView中某种破坏的内部状态,只要UICollectionViewController辞职第一响应者(因为孩子成为第一响应者)就会强制更新。

这似乎不是正确的解决方案,所以我没有将其标记为答案,但是如果其他人遇到问题,这就是我目前正在努力解决的问题。

1 个答案:

答案 0 :(得分:0)

在我看来,这似乎是某种处理第一响应者的内部状态。

我发现的一个解决方法是通过添加额外的索引使每个补充视图的索引路径唯一:

- (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:正在或测试索引路径上的相等性(例如,使用isEqual:),那么此解决方法可能会破坏它。您必须确保仅比较sectionitem以保持相同的功能。