Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UICollectionView section headers flicker issue

This post comes (perhaps stupidly) after 8 straight hours of gawping at my computer like some stupified monkey, because of an issue with UICollectionView on iOS 7.

I have subclassed UICollectionViewFlowLayout to provide a generic "Section X" (Sticky Header) [where X is a number] header for all 50 sections of my UICollectionView dataSource, which is an NSArray partitioned.

I invoke - (NSArray *) layoutAttributesForElementsInRect:(CGRect)rect { in my subclass, which does show the header, but only for the first section. It's extremely odd behaviour. What I expect is:

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

"SECT 2" is the next section header after the first, that should be visible on screen while the user scrolls horizontally (same applies for vertical) which but what I get is:

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

A blank section header following the first one, as well as the second section header being in the wrong place. This all changes when I scroll the UICollectionView. The second one in the wrong place disappears, but it doesn't go to where it should be either.

After scrolling ever so slightly on:

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

Still blanks following Section 1.

None of the section headers are actually VISIBLE in the UICollectionView until I actually scroll to the beginning of that section. Instead of scrolling into place, it just appears at the correct location, with no animation whatsoever. I keep scrolling and it's the same behaviour.

I have tested this behaviour without my UICollectionViewFlowLayout subclass, and just a generic UIView pasted on the screen. On iOS 6 this problem is not there. The headers seem to dequeue and display correctly the whole way through the scroll, without the slightest issue whatsoever.

Can anybody help me, or as anybody else experienced this issue in giving UICollectionView section headers on iOS 7? I'm losing my mind!!

layoutAttributesForElementsInRect: method

    - (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: relevant code:

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;
like image 409
topLayoutGuide Avatar asked Dec 19 '22 18:12

topLayoutGuide


1 Answers

I solved my issue. It turns out that under iOS 7 inside

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

You MUST NOT EVER set the frame of your Supplementary View. Leave that for the appropriate delegate methods.

My goodness. 17 hours later, I'm going to bed.

like image 114
topLayoutGuide Avatar answered Jan 04 '23 06:01

topLayoutGuide