UICollectionView 部分标题闪烁问题

Posted

技术标签:

【中文标题】UICollectionView 部分标题闪烁问题【英文标题】:UICollectionView section headers flicker issue 【发布时间】:2014-01-30 12:03:28 【问题描述】:

由于 ios 7 上的 UICollectionView 存在问题,我连续 8 小时盯着我的电脑(可能是愚蠢的)发了这篇文章(可能是愚蠢的)。

我对@9​​87654323@ 进行了子类化,以便为我的 UICollectionView 数据源的所有 50 个部分提供一个通用的“Section X”(粘性标题)[其中 X 是一个数字]标题,这是一个 NSArray 分区。

我在我的子类中调用- (NSArray *) layoutAttributesForElementsInRect:(CGRect)rect ,它确实显示了标题,但仅用于第一部分。这是非常奇怪的行为。我的期望是:

|S| [CELL] [CELL] |S| [CELL] [CELL] 
|E| [    ] [    ] |E| [    ] [    ] 
|C| [____] [____] |C| [____] [____] 
|T|               |T|
| | [CELL] [CELL] | | [CELL] 
| | [    ] [    ] | | [    ] 
|1| [____] [____] |2| [____]

“SECT 2” 是第一个部分之后的下一个部分标题,当用户水平滚动(垂直方向相同)时,应该在屏幕上可见,但是什么我得到的是:

|S| [CELL] [CELL] | | [CELL] [CELL] 
|E| [    ] [    ] | | [    ] [    ] 
|C| [____] [____] | | [____] [____] 
|T|               | |
| | [CELL] [CELL] | | [CELL] 
| | [    ] [    ] | | [    ] 
|2| [____] [____] | | [____]

第一个节标题之后的空白节标题,以及第二个节标题的位置错误。当我滚动 UICollectionView 时,这一切都会改变。第二个在错误的地方消失了,但它也没有去它应该在的地方。

在稍微滚动之后:

|S| [CELL] [CELL] | | [CELL] [CELL] 
|E| [    ] [    ] | | [    ] [    ] 
|C| [____] [____] | | [____] [____] 
|T|               | |
| | [CELL] [CELL] | | [CELL] 
| | [    ] [    ] | | [    ] 
|1| [____] [____] | | [____]

在第 1 节之后仍然是空白。

在我真正滚动到该部分的开头之前,UICollectionView 中的任何部分标题实际上都不可见。它没有滚动到位,而是出现在正确的位置,没有任何动画。我一直在滚动,这是相同的行为。

我已经在没有UICollectionViewFlowLayout 子类的情况下测试了这种行为,只是在屏幕上粘贴了一个通用的UIView。在 iOS 6 上,这个问题不存在。标题似乎在整个滚动过程中出列并正确显示,没有任何问题。

任何人都可以帮助我,或者其他人在 iOS 7 上给出 UICollectionView 部分标题时遇到过这个问题吗?我疯了!!

layoutAttributesForElementsInRect:方法

    - (NSArray *) layoutAttributesForElementsInRect:(CGRect)rect 

    NSMutableArray *answer = [[super layoutAttributesForElementsInRect:rect] mutableCopy];
    UICollectionView * const cv = self.collectionView;
    CGPoint const contentOffset = cv.contentOffset;

    NSMutableIndexSet *missingSections = [NSMutableIndexSet indexSet];
    for (UICollectionViewLayoutAttributes *layoutAttributes in answer) 
        if (layoutAttributes.representedElementCategory == UICollectionElementCategoryCell) 
            [missingSections addIndex:layoutAttributes.indexPath.section];
        
    
    for (UICollectionViewLayoutAttributes *layoutAttributes in answer) 
        if ([layoutAttributes.representedElementKind isEqualToString:UICollectionElementKindSectionHeader]) 
            [missingSections removeIndex:layoutAttributes.indexPath.section];
        
    

    [missingSections enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) 

        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:idx];

        UICollectionViewLayoutAttributes *layoutAttributes = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:indexPath];

        [answer addObject:layoutAttributes];

    ];

    for (UICollectionViewLayoutAttributes *layoutAttributes in answer) 

        if ([layoutAttributes.representedElementKind isEqualToString:UICollectionElementKindSectionHeader]) 

            NSInteger section = layoutAttributes.indexPath.section;
            NSInteger numberOfItemsInSection = [cv numberOfItemsInSection:section];

            NSIndexPath *firstCellIndexPath = [NSIndexPath indexPathForItem:0 inSection:section];
            NSIndexPath *lastCellIndexPath = [NSIndexPath indexPathForItem:MAX(0, (numberOfItemsInSection - 1)) inSection:section];

            UICollectionViewLayoutAttributes *firstCellAttrs = [self layoutAttributesForItemAtIndexPath:firstCellIndexPath];
            UICollectionViewLayoutAttributes *lastCellAttrs = [self layoutAttributesForItemAtIndexPath:lastCellIndexPath];

            CGFloat headerWidth = CGRectGetWidth(layoutAttributes.frame);
            CGPoint origin = layoutAttributes.frame.origin;
            origin.x = MIN(MAX(contentOffset.x, (CGRectGetMinX(firstCellAttrs.frame) - headerWidth)),
                           (CGRectGetMaxX(lastCellAttrs.frame) - headerWidth)
                           );

            layoutAttributes.zIndex = 1024;
            layoutAttributes.frame = (CGRect)
                .origin = origin,
                .size = layoutAttributes.frame.size
            ;

        

    

    return answer;


viewForSupplementaryElementOfKind:相关代码:

CollectionHeaderView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:
                                            UICollectionElementKindSectionHeader withReuseIdentifier:CellIdentifier forIndexPath:indexPath];

        headerView.frame = CGRectMake(0, 0, 60, sectionContainerView.frame.size.height);
[headerView setBackgroundColor:[UIColor greenColor]]; //to test visibility
return headerView;

【问题讨论】:

我不知道你的布局有什么问题,但我在uicollectionview-gridlayout 中有一个强大的粘性标题实现,它可能会给你一些指示。或者,如果您想使用它,它目前只进行垂直滚动,但水平将是一个简单的添加。 不幸的是,我不知道如何将 Horizo​​ntal 添加到您的子类中,甚至不知道如何使用它。我很抱歉。 我并不是建议您进行更改。 我从 IB 关闭了我的子类,这意味着它使用来自 Apple 的默认流。而且只有一个部分标题,固定在屏幕左侧,其他部分不显示。 【参考方案1】:

我解决了我的问题。原来在iOS 7里面

- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath

绝不能设置补充视图的框架。将其留给适当的委托方法。

我的天哪。 17 小时后,我要睡觉

【讨论】:

以上是关于UICollectionView 部分标题闪烁问题的主要内容,如果未能解决你的问题,请参考以下文章

UICollectionView 导航栏闪烁

UICollectionView reloadData 但查看闪烁

UICollectionView多个单元格(UICollectionViewCell)在Objective-C中闪烁同步

自动无限collectionView - 闪烁

DiffableDataSource - 无动画,但在删除操作期间闪烁

如何在 Collection View 中给 UILabel 一个闪烁效果