如何使UICollectionView的Header悬浮

http://stackoverflow.com/questions/31203759/sticky-uicollectionview-header

Summary: Describes a solution creating sticky headers for UICollectionView using UICollectionElementKindSectionHeader-kind elements that scrolls with the content, which works like the standard UITableView headers.


Congratulations if you’re using UICollectionView: you’re in a world of surprise and delight.

Default header and footer implementation in UICollectionViewFlowLayout scrolls everything in one go, so headers may go off-screen as you scroll. These rules keep them on-screen:

  • The header should be positioned so it can never go further up than one header height above the first cell in the section.
  • The header should be positioned so it can never go further down than one header header height above the lower bounds of the last cell in the section.
  • The header should be positioned so it usually stays around the top edge, referencing the content offset of the collection view.

The solution is to implement a UICollectionViewFlowLayout subclass and override two methods, -shouldInvalidateLayoutForBoundsChange: and -layoutAttributesForElementsInRect:.

When you set up the layout to be queried every time for a bounds change, it will be queried whenever the user scrolls, because scrolling in UIScrollView is implemented by changing the origin of the underlying bounds of the layer.

It is also very important to override -layoutAttributesForElementsInRect:, which serves two purposes. You must adjust layout attributes for each header element, and you need to manually insert attributes for missing headers because by default, UICollectionViewFlowLayout only emits attributes for headers that are in the bounds. (UICollectionView looks at all the attributes and maps them to existing or newly-created views.)

Here’s the code. Note that the zIndex is raised for headers, which is important because now they are supposed to overlap the cells in the same section. Without the zIndexconfigured, everything will be laid using the same zIndex and the front/back order will be undefined.

- (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];

            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
            };

        }

    }

    return answer;

}

- (BOOL) shouldInvalidateLayoutForBoundsChange:(CGRect)newBound {

    return YES;

}


转自:http://blog.radi.ws/post/32905838158/sticky-headers-for-uicollectionview-using 

参考: http://www.vigorouscoding.com/2013/03/uicollectionview-with-sticky-headers/ 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值