-
-
Save nspassov/ab4bcb0bab578517e026b2edbb03c1df to your computer and use it in GitHub Desktop.
UICollectionView with sticky headers which works for horizontal as well as vertical scrolling
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
#import <UIKit/UIKit.h> | |
@interface DateFlowLayout : 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
@implementation DateFlowLayout | |
-(id)initWithCoder:(NSCoder *)aDecoder { | |
self = [super initWithCoder:aDecoder]; | |
self.scrollDirection = UICollectionViewScrollDirectionHorizontal; | |
self.headerReferenceSize = CGSizeMake(50, 50); | |
self.minimumInteritemSpacing = 0; | |
self.minimumLineSpacing = 0; | |
self.sectionInset = UIEdgeInsetsMake(0, 0, 0, 0); | |
return self; | |
} | |
-(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]; | |
if (self.scrollDirection == UICollectionViewScrollDirectionVertical) { | |
CGFloat headerHeight = CGRectGetHeight(layoutAttributes.frame); | |
CGPoint origin = layoutAttributes.frame.origin; | |
origin.y = MIN( | |
MAX(contentOffset.y, (CGRectGetMinY(firstCellAttrs.frame) - headerHeight)), | |
(CGRectGetMaxY(lastCellAttrs.frame) - headerHeight) | |
); | |
layoutAttributes.zIndex = 1024; | |
layoutAttributes.frame = (CGRect){ | |
.origin = origin, | |
.size = layoutAttributes.frame.size | |
}; | |
} else { | |
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; | |
} | |
-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBound { | |
return YES; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment