1111@implementation FloatingHeaderFlowLayout
1212
1313- (NSArray *)layoutAttributesForElementsInRect : (CGRect)rect {
14+ NSMutableArray *layoutAttributes = [[super layoutAttributesForElementsInRect: rect] mutableCopy ];
1415
15- NSMutableArray *answer = [[super layoutAttributesForElementsInRect: rect] mutableCopy ];
16- UICollectionView * const cv = self.collectionView ;
17- CGPoint contentOffset = cv.contentOffset ;
18- contentOffset.y = contentOffset.y + cv.contentInset .top ;
19- NSMutableIndexSet *missingSections = [NSMutableIndexSet indexSet ];
20- for (UICollectionViewLayoutAttributes *layoutAttributes in answer) {
21- if (layoutAttributes.representedElementCategory == UICollectionElementCategoryCell) {
22- [missingSections addIndex: layoutAttributes.indexPath.section];
16+ NSMutableIndexSet *headersNeedingLayout = [NSMutableIndexSet indexSet ];
17+ for (UICollectionViewLayoutAttributes *attributes in layoutAttributes) {
18+ if (attributes.representedElementCategory == UICollectionElementCategoryCell) {
19+ [headersNeedingLayout addIndex: attributes.indexPath.section];
2320 }
2421 }
25- for (UICollectionViewLayoutAttributes *layoutAttributes in answer ) {
26- if ([layoutAttributes .representedElementKind isEqualToString: UICollectionElementKindSectionHeader]) {
27- [missingSections removeIndex: layoutAttributes .indexPath.section];
22+ for (UICollectionViewLayoutAttributes *attributes in layoutAttributes ) {
23+ if ([attributes .representedElementKind isEqualToString: UICollectionElementKindSectionHeader]) {
24+ [headersNeedingLayout removeIndex: attributes .indexPath.section];
2825 }
2926 }
3027
31- [missingSections enumerateIndexesUsingBlock: ^(NSUInteger idx, BOOL *stop) {
32-
28+ [headersNeedingLayout enumerateIndexesUsingBlock: ^(NSUInteger idx, BOOL *stop) {
3329 NSIndexPath *indexPath = [NSIndexPath indexPathForItem: 0 inSection: idx];
34-
35- UICollectionViewLayoutAttributes *layoutAttributes = [self layoutAttributesForSupplementaryViewOfKind: UICollectionElementKindSectionHeader atIndexPath: indexPath];
36- if (layoutAttributes != nil ) {
37- [answer addObject: layoutAttributes];
30+ UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForSupplementaryViewOfKind: UICollectionElementKindSectionHeader atIndexPath: indexPath];
31+ if (attributes != nil ) {
32+ [layoutAttributes addObject: attributes];
3833 }
39-
4034 }];
4135
42- for (UICollectionViewLayoutAttributes *layoutAttributes in answer) {
43-
44- if ([layoutAttributes.representedElementKind isEqualToString: UICollectionElementKindSectionHeader]) {
45-
46- NSInteger section = layoutAttributes.indexPath .section ;
47- if (section >= cv.numberOfSections ) {
48- return answer;
36+ for (UICollectionViewLayoutAttributes *attributes in layoutAttributes) {
37+ if ([attributes.representedElementKind isEqualToString: UICollectionElementKindSectionHeader]) {
38+ NSInteger section = attributes.indexPath .section ;
39+ if (section >= self.collectionView .numberOfSections ) {
40+ return layoutAttributes;
4941 }
50- NSInteger numberOfItemsInSection = [cv numberOfItemsInSection: section];
51-
52- NSIndexPath *firstCellIndexPath = [NSIndexPath indexPathForItem: 0 inSection: section];
53- NSIndexPath *lastCellIndexPath = [NSIndexPath indexPathForItem: MAX (0 , (numberOfItemsInSection - 1 )) inSection: section];
42+ NSInteger numberOfItemsInSection = [self .collectionView numberOfItemsInSection: section];
5443
55- UICollectionViewLayoutAttributes *firstCellAttrs = [self layoutAttributesForItemAtIndexPath: firstCellIndexPath ];
56- UICollectionViewLayoutAttributes *lastCellAttrs = [self layoutAttributesForItemAtIndexPath: lastCellIndexPath ];
44+ NSIndexPath *indexPathFirstItem = [NSIndexPath indexPathForItem: 0 inSection: section ];
45+ NSIndexPath *indexPathLastItem = [NSIndexPath indexPathForItem: MAX ( 0 , (numberOfItemsInSection - 1 )) inSection: section ];
5746
58- CGFloat headerHeight = CGRectGetHeight (layoutAttributes.frame );
59- CGPoint origin = layoutAttributes.frame .origin ;
60- origin.y = MIN (
61- MAX (
62- contentOffset.y ,
63- (CGRectGetMinY (firstCellAttrs.frame ) - headerHeight)
64- ),
65- (CGRectGetMaxY (lastCellAttrs.frame ) - headerHeight)
66- );
47+ UICollectionViewLayoutAttributes *attributesFirstItem = [self layoutAttributesForItemAtIndexPath: indexPathFirstItem];
48+ UICollectionViewLayoutAttributes *attributesLastItem = [self layoutAttributesForItemAtIndexPath: indexPathLastItem];
6749
68- layoutAttributes.zIndex = 1024 ;
69- layoutAttributes.frame = (CGRect) {
70- .origin = origin,
71- .size = layoutAttributes.frame .size
72- };
50+ CGRect frame = attributes.frame ;
51+ CGFloat offset = self.collectionView .contentOffset .y + self.collectionView .contentInset .top ;
7352
53+ CGFloat minY = CGRectGetMinY (attributesFirstItem.frame ) - frame.size .height ;
54+ CGFloat maxY = CGRectGetMaxY (attributesLastItem.frame ) - frame.size .height ;
55+ CGFloat posY = MIN (MAX (offset, minY), maxY);
56+ frame.origin .y = posY;
57+ attributes.frame = frame;
58+ attributes.zIndex = 1024 ;
7459 }
75-
7660 }
77-
78- return answer;
79-
61+ return layoutAttributes;
8062}
8163
82- - (BOOL ) shouldInvalidateLayoutForBoundsChange : (CGRect)newBound {
83-
64+ - (BOOL )shouldInvalidateLayoutForBoundsChange : (CGRect)newBound {
8465 return YES ;
85-
8666}
8767
8868- (CGSize)collectionViewContentSize {
69+ // Lets the collection view hide the searchbar on load, if there are only few items in the view
8970 CGSize size = [super collectionViewContentSize ];
90- if (size.height < self.collectionView .frame .size .height + searchBarHeight) {
91- size.height = self.collectionView .frame .size .height + searchBarHeight;
92- }
71+ size.height = MAX (size.height , self.collectionView .frame .size .height + searchBarHeight);
9372 return size;
9473}
9574
@@ -98,10 +77,10 @@ - (void)setSearchBarHeight:(CGFloat)height {
9877}
9978
10079- (CGPoint)targetContentOffsetForProposedContentOffset : (CGPoint)proposedContentOffset withScrollingVelocity : (CGPoint)velocity {
80+ // If searchbar is partially shown, snap to a position either showing (>=50% revealed) or hiding it (<50% revealed).
10181 CGFloat offsetAdjustment = 0 ;
10282 CGFloat threshold = searchBarHeight / 2 ;
103- CGFloat contentOffsetInset = proposedContentOffset.y ;
104- contentOffsetInset = contentOffsetInset + self.collectionView .contentInset .top ;
83+ CGFloat contentOffsetInset = proposedContentOffset.y + self.collectionView .contentInset .top ;
10584 if (contentOffsetInset <= threshold) {
10685 offsetAdjustment = -contentOffsetInset;
10786 }
0 commit comments