【问题标题】:UICollectionView not re-displaying supplementary views scrolled off screen when keyboard is visible当键盘可见时,UICollectionView 不会重新显示滚动到屏幕外的补充视图
【发布时间】:2014-10-01 02:55:38
【问题描述】:

我有一个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 重现此问题,该UIView 设置了inputView 并成为第一响应者。当键盘在 CellA [0, 0] 元素中的文本字段上处于活动状态并且您将其上方的补充视图滚动到屏幕外然后再打开时,这些视图不会重新添加到集合视图中。

在我的调查中,我发现UICollectionReusableView 子类被放置到重用队列中,并在视图层次结构中显示为hidden=YES,正如等待重用时所预期的那样。当键盘不活动时,我重新滚动元素,之前显示的类的相同实例将被重用并显示在屏幕上。

我尝试让UICollectionViewLayout 要求对每个边界更改进行重新布局(通过从-shouldInvalidateLayoutForBoundsChange: 返回YES);这没有任何效果,元素最终仍被隐藏。

我无法在 Internet 上找到有关此问题的任何其他报告,但我已经在 Xcode 5.1.1 的 iOS 模拟器 7.1 和运行 iOS 7.1.2 的 iPod Touch 上重现了它。


我已经用一个可能的解决方法更新了上面的 repo:

- (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 辞去第一响应者(因为孩子成为第一响应者)时强制更新来解决。

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

【问题讨论】:

    标签: ios cocoa-touch uicollectionview


    【解决方案1】:

    在我看来,这绝对是某种内部状态,用于处理即将崩溃的第一响应者。

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

    - (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 值,这也意味着您不必继承 @987654324 @ 强制它在辞去第一响应者时更新。

    但是,如果您当前正在 compare:-ing 或测试索引路径上的相等性(例如使用 isEqual:),那么此解决方法可能会破坏这一点。相反,您必须确保只比较 sectionitem 以保持相同的功能。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-23
      • 1970-01-01
      相关资源
      最近更新 更多