StickyHeaderFlowLayout - UICollectionView的section header 懸停

jopen 10年前發布 | 18K 次閱讀 Objective-C開發

StickyHeaderFlowLayout

實現UICollectionView的section header懸停效果.效果和UITableView的plain模式下的header section效果相同,支持指定某一個或者多個sction header的懸停

關鍵在于設置下面的這個屬性

@property (nonatomic,strong) NSArray<NSNumber *> *stickySections;

image

使用示例 EXAMPLE

將我們的UICollectionView的布局替換為YLStickyHeaderFlowLayout即可

YLStickyHeaderFlowLayout核心源碼

- (NSArray *) layoutAttributesForElementsInRect:(CGRect)rect {
    if (self.disableStickyFlow) {
        return [super layoutAttributesForElementsInRect:rect];
    }
    NSMutableArray<UICollectionViewLayoutAttributes *> *allItems ;
    //collectionView中的item(包括cell和header、footer這些)的《結構信息》.關鍵!!!!cell,header,footer都是利用這個數組的,在這個中,原來創建的section等,要按順序存放到數組中來!
    NSArray *originalAttributes = [super layoutAttributesForElementsInRect:rect];
    //allItems = (NSMutableArray *)originalAttributes ;
    allItems = [originalAttributes mutableCopy];//實際上layoutAttributesForElementsInRect返回的是NSMutableArray,所以,可以直接強轉

    NSMutableDictionary *headers = [[NSMutableDictionary alloc] init];//存放每個section的header
    NSMutableDictionary<NSNumber *,UICollectionViewLayoutAttributes *> *lastCells = [[NSMutableDictionary alloc] init];//存放的是每個section的最后一個cell
    [allItems enumerateObjectsUsingBlock:^(UICollectionViewLayoutAttributes * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {

        NSIndexPath *indexPath = [obj indexPath];
        BOOL isHeader = [[obj representedElementKind] isEqualToString:UICollectionElementKindSectionHeader];
        BOOL isFooter = [[obj representedElementKind] isEqualToString:UICollectionElementKindSectionFooter];

        if (isHeader) {
            headers[@(indexPath.section)] = obj;
        } else if (isFooter) {
            // 不處理
        } else {
            //其實用這兩句也是可以的
            //NSNumber *sectionObj = @(indexPath.section);
            //lastCells[sectionObj] = obj;

            UICollectionViewLayoutAttributes *currentAttribute = lastCells[@(indexPath.section)];
            // 確保取到的是section中最后一個cell
            if ( ! currentAttribute || indexPath.row > currentAttribute.indexPath.row) {
                [lastCells setObject:obj forKey:@(indexPath.section)];
            }
        }

        //如果按照正常情況下,header離開屏幕被系統回收,而header的層次關系又與cell相等,如果不去理會,會出現cell在header上面的情況
        //通過打印可以知道cell的層次關系zIndex數值為0,我們可以將header的zIndex設置成1,如果不放心,也可以將它設置成非常大,這里隨便填了個1024
        if (isHeader) {
            obj.zIndex = 1024;
        } else {
            // For iOS 7.0, the cell zIndex should be above sticky section header
            obj.zIndex = 1;
        }

    }];


    [lastCells enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull key, UICollectionViewLayoutAttributes * _Nonnull obj, BOOL * _Nonnull stop) {
        NSIndexPath *indexPath = obj.indexPath;
        NSNumber *indexPathKey = @(indexPath.section);

        UICollectionViewLayoutAttributes *header = headers[indexPathKey];

        if ( ! header) {
            // CollectionView自動將不再bounds內的headers移除了,所以,Headers可能為nil.這種情況下我們需要重新將其加回來 automatically removes headers not in bounds
            header = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader
                                                          atIndexPath:[NSIndexPath indexPathForItem:0 inSection:indexPath.section]];

            if (!CGSizeEqualToSize(CGSizeZero, header.frame.size)) {
                [allItems addObject:header];
            }
        }
        if (!CGSizeEqualToSize(CGSizeZero, header.frame.size)) {
            [self updateHeaderAttributes:header lastCellAttributes:lastCells[indexPathKey]];
        }
    }];


    return allItems;

}

項目地址: https://github.com/yohunl/StickyHeaderFlowLayout

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!