Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cute/ae147d4bc32a9c10341bab4c8b93eec2 to your computer and use it in GitHub Desktop.
Save cute/ae147d4bc32a9c10341bab4c8b93eec2 to your computer and use it in GitHub Desktop.
A subclass of UICollectionViewFlowLayout which has UITableView style sticky headers.
// StickyHeadersCollectionViewFlowLayout
//
// A subclass of UICollectionViewFlowLayout which has UITableView style sticky headers.
//
// This code is based on Evadne Wu's code^1, with the following changes:
//
// * Fixes a crash for sections with zero items
// * Adds support for UIScrollView's contentInset
// * Adds support for UICollectionViewFlowLayout's sectionInset
//
// [1]: http://blog.radi.ws/post/32905838158/sticky-headers-for-uicollectionview-using
@implementation StickyHeadersCollectionViewFlowLayout
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSMutableArray * attributesArray = [[super layoutAttributesForElementsInRect: rect] mutableCopy];
UICollectionView * const cv = self.collectionView;
CGPoint const contentOffset = cv.contentOffset;
UIEdgeInsets contentInset = cv.contentInset;
UIEdgeInsets sectionInset = self.sectionInset;
NSMutableIndexSet *missingSections = [NSMutableIndexSet indexSet];
for (UICollectionViewLayoutAttributes *layoutAttributes in attributesArray) {
if (layoutAttributes.representedElementCategory == UICollectionElementCategoryCell) {
[missingSections addIndex:layoutAttributes.indexPath.section];
}
}
for (UICollectionViewLayoutAttributes *layoutAttributes in attributesArray) {
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];
[attributesArray addObject:layoutAttributes];
}];
for (UICollectionViewLayoutAttributes *layoutAttributes in attributesArray) {
if ([layoutAttributes.representedElementKind isEqualToString:UICollectionElementKindSectionHeader]) {
NSInteger section = layoutAttributes.indexPath.section;
NSInteger numberOfItemsInSection = [cv numberOfItemsInSection:section];
// If the UICollectionView implements the Flow Layout specific delegate methods, ask that for a section inset (which can be different for individual sections, compared to the self.sectionInset property)
id <UICollectionViewDelegate> delegate = cv.delegate;
if([delegate respondsToSelector:@selector(collectionView:layout:insetForSectionAtIndex:)]){
id <UICollectionViewDelegateFlowLayout> flowDelegate = (id <UICollectionViewDelegateFlowLayout>) cv.delegate;
sectionInset = [flowDelegate collectionView:cv layout:cv insetForSectionAtIndex:section];
}
if (numberOfItemsInSection > 0) {
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 headerHeight = CGRectGetHeight(layoutAttributes.frame);
CGPoint origin = layoutAttributes.frame.origin;
origin.y = MIN(
MAX(
contentOffset.y + contentInset.top,
(CGRectGetMinY(firstCellAttrs.frame) - headerHeight - sectionInset.top)
),
(CGRectGetMaxY(lastCellAttrs.frame) - headerHeight)
);
layoutAttributes.zIndex = 1024;
layoutAttributes.frame = (CGRect){
.origin = origin,
.size = layoutAttributes.frame.size
};
}
}
}
return attributesArray;
}
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {
return YES;
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment