Last active
August 14, 2023 05:04
-
-
Save evadne/4544569 to your computer and use it in GitHub Desktop.
Todd Laney’s enhancements to Sticky Headers + UICollectionViewFlowLayout
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// StickyHeaderLayout.h | |
// Wombat | |
// | |
// Created by Todd Laney on 1/9/13. | |
// Copyright (c) 2013 ToddLa. All rights reserved. | |
// | |
// Modified from http://blog.radi.ws/post/32905838158/sticky-headers-for-uicollectionview-using THANKS! | |
// | |
#import <UIKit/UIKit.h> | |
@interface StickyHeaderLayout : UICollectionViewFlowLayout | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// StickyHeaderFlowLayout.m | |
// Wombat | |
// | |
// Created by Todd Laney on 1/9/13. | |
// Copyright (c) 2013 ToddLa. All rights reserved. | |
// | |
// Modified from http://blog.radi.ws/post/32905838158/sticky-headers-for-uicollectionview-using THANKS! | |
// | |
#import "StickyHeaderFlowLayout.h" | |
@implementation StickyHeaderFlowLayout | |
- (NSArray *) layoutAttributesForElementsInRect:(CGRect)rect { | |
NSMutableArray *answer = [[super layoutAttributesForElementsInRect:rect] mutableCopy]; | |
NSMutableIndexSet *missingSections = [NSMutableIndexSet indexSet]; | |
for (NSUInteger idx=0; idx<[answer count]; idx++) { | |
UICollectionViewLayoutAttributes *layoutAttributes = answer[idx]; | |
if (layoutAttributes.representedElementCategory == UICollectionElementCategoryCell) { | |
[missingSections addIndex:layoutAttributes.indexPath.section]; // remember that we need to layout header for this section | |
} | |
if ([layoutAttributes.representedElementKind isEqualToString:UICollectionElementKindSectionHeader]) { | |
[answer removeObjectAtIndex:idx]; // remove layout of header done by our super, we will do it right later | |
idx--; | |
} | |
} | |
// layout all headers needed for the rect using self code | |
[missingSections enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) { | |
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:idx]; | |
UICollectionViewLayoutAttributes *layoutAttributes = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:indexPath]; | |
[answer addObject:layoutAttributes]; | |
}]; | |
return answer; | |
} | |
- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { | |
UICollectionViewLayoutAttributes *attributes = [super layoutAttributesForSupplementaryViewOfKind:kind atIndexPath:indexPath]; | |
if ([kind isEqualToString:UICollectionElementKindSectionHeader]) { | |
UICollectionView * const cv = self.collectionView; | |
CGPoint const contentOffset = cv.contentOffset; | |
CGPoint nextHeaderOrigin = CGPointMake(INFINITY, INFINITY); | |
if (indexPath.section+1 < [cv numberOfSections]) { | |
UICollectionViewLayoutAttributes *nextHeaderAttributes = [super layoutAttributesForSupplementaryViewOfKind:kind atIndexPath:[NSIndexPath indexPathForItem:0 inSection:indexPath.section+1]]; | |
nextHeaderOrigin = nextHeaderAttributes.frame.origin; | |
} | |
CGRect frame = attributes.frame; | |
if (self.scrollDirection == UICollectionViewScrollDirectionVertical) { | |
frame.origin.y = MIN(MAX(contentOffset.y, frame.origin.y), nextHeaderOrigin.y - CGRectGetHeight(frame)); | |
} | |
else { // UICollectionViewScrollDirectionHorizontal | |
frame.origin.x = MIN(MAX(contentOffset.x, frame.origin.x), nextHeaderOrigin.x - CGRectGetWidth(frame)); | |
} | |
attributes.zIndex = 1024; | |
attributes.frame = frame; | |
} | |
return attributes; | |
} | |
- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { | |
UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForSupplementaryViewOfKind:kind atIndexPath:indexPath]; | |
return attributes; | |
} | |
- (UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { | |
UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForSupplementaryViewOfKind:kind atIndexPath:indexPath]; | |
return attributes; | |
} | |
- (BOOL) shouldInvalidateLayoutForBoundsChange:(CGRect)newBound { | |
return YES; | |
} | |
@end |
Very slow
sometimes next section should not show cells but header should be still visible.
it that case the code above hide header as well.
To fix that no need to check for
if (layoutAttributes.representedElementCategory == UICollectionElementCategoryCell)
because we need to add to missingSections everything (even header indexPath.section)
Can you please provide the code in Swift 3.0?
Maybe can add the sectionInset of collectionView, like this:
`
if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {
frame.origin.x += self.sectionInset.left;
frame.origin.y = MIN(MAX(contentOffset.y, frame.origin.y) + self.sectionInset.bottom, nextHeaderOrigin.y + self.sectionInset.bottom - CGRectGetHeight(frame));
} else { // UICollectionViewScrollDirectionHorizontal
frame.origin.x = MIN(MAX(contentOffset.x, frame.origin.x) + self.sectionInset.left, nextHeaderOrigin.x + self.sectionInset.left - CGRectGetWidth(frame));
frame.origin.y += self.sectionInset.top;
}
frame.size = CGSizeMake(frame.size.width - self.sectionInset.left - self.sectionInset.bottom, frame.size.height - self.sectionInset.top - self.sectionInset.bottom);`
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I agree with @r3econ.
the implementation of layoutAttributesForElementsInRect: is not quite straight-forward.
I make a little modification at:
https://gist.github.com/haojianzong/209251d1fc171705bbee