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;
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With