Skip to content

Instantly share code, notes, and snippets.

@randomsequence
Last active October 26, 2016 14:57

Revisions

  1. randomsequence revised this gist Jun 13, 2013. 1 changed file with 12 additions and 0 deletions.
    12 changes: 12 additions & 0 deletions StickyHeadersCollectionViewFlowLayout.m
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,15 @@
    // 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
  2. randomsequence created this gist Jun 13, 2013.
    74 changes: 74 additions & 0 deletions StickyHeadersCollectionViewFlowLayout.m
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,74 @@
    @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 (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