Forked from toblerpwn/CustomCollectionFlowLayout.h
Last active
January 1, 2016 08:59
-
-
Save taybenlor/8121827 to your computer and use it in GitHub Desktop.
Adds support for sections with no header.
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
// | |
// CustomCollectionFlowLayout.h | |
// evilapples | |
// | |
// http://stackoverflow.com/questions/13511733/how-to-make-supplementary-view-float-in-uicollectionview-as-section-headers-do-i | |
// | |
// | |
#import <UIKit/UIKit.h> | |
@interface CustomCollectionFlowLayout : 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
// | |
// CustomCollectionFlowLayout.m | |
// evilapples | |
// | |
// http://stackoverflow.com/questions/13511733/how-to-make-supplementary-view-float-in-uicollectionview-as-section-headers-do-i | |
// | |
// | |
#import "CustomCollectionFlowLayout.h" | |
@implementation CustomCollectionFlowLayout | |
- (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]; | |
if (layoutAttributes) { | |
[answer addObject:layoutAttributes]; | |
} | |
}]; | |
for (UICollectionViewLayoutAttributes *layoutAttributes in answer) { | |
if ([layoutAttributes.representedElementKind isEqualToString:UICollectionElementKindSectionHeader]) { | |
NSInteger section = layoutAttributes.indexPath.section; | |
NSInteger numberOfItemsInSection = [cv numberOfItemsInSection:section]; | |
NSIndexPath *firstObjectIndexPath = [NSIndexPath indexPathForItem:0 inSection:section]; | |
NSIndexPath *lastObjectIndexPath = [NSIndexPath indexPathForItem:MAX(0, (numberOfItemsInSection - 1)) inSection:section]; | |
BOOL cellsExist; | |
UICollectionViewLayoutAttributes *firstObjectAttrs; | |
UICollectionViewLayoutAttributes *lastObjectAttrs; | |
if (numberOfItemsInSection > 0) { // use cell data if items exist | |
cellsExist = YES; | |
firstObjectAttrs = [self layoutAttributesForItemAtIndexPath:firstObjectIndexPath]; | |
lastObjectAttrs = [self layoutAttributesForItemAtIndexPath:lastObjectIndexPath]; | |
} else { // else use the header and footer | |
cellsExist = NO; | |
firstObjectAttrs = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader | |
atIndexPath:firstObjectIndexPath]; | |
lastObjectAttrs = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionFooter | |
atIndexPath:lastObjectIndexPath]; | |
} | |
CGFloat topHeaderHeight = (cellsExist) ? CGRectGetHeight(layoutAttributes.frame) : 0; | |
CGFloat bottomHeaderHeight = CGRectGetHeight(layoutAttributes.frame); | |
CGRect frameWithEdgeInsets = UIEdgeInsetsInsetRect(layoutAttributes.frame, | |
cv.contentInset); | |
CGPoint origin = frameWithEdgeInsets.origin; | |
origin.y = MIN( | |
MAX( | |
contentOffset.y + cv.contentInset.top, | |
(CGRectGetMinY(firstObjectAttrs.frame) - topHeaderHeight) | |
), | |
(CGRectGetMaxY(lastObjectAttrs.frame) - bottomHeaderHeight) | |
); | |
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