自定义UICollectionViewLayout

效果如图:



自定义UICollectionViewLayout 除了计算比较麻烦,其他控制还蛮方便
先贴关键代码,等有时间在写注释:

@interface WMTopUpLayout ()

/** 包含 header 和 footer */
@property (nonatomic, strong) NSMutableArray *layoutInfoArray;

/** 不包含 header 和 footer */
@property (nonatomic, strong) NSMutableArray *itemLayoutInfoArray;

@property (nonatomic, assign) CGSize contentSize;

@end

@implementation WMTopUpLayout

- (NSMutableArray *)layoutInfoArray {
    if (!_layoutInfoArray) {

        _layoutInfoArray = [[NSMutableArray alloc] init];

    }
    return _layoutInfoArray;
}

- (NSMutableArray *)itemLayoutInfoArray {
    if (!_itemLayoutInfoArray) {

        _itemLayoutInfoArray = [[NSMutableArray alloc] init];

    }
    return _itemLayoutInfoArray;
}


/** 
    The collection view calls -prepareLayout once at its first layout as the first message to the layout instance.
    The collection view calls -prepareLayout again after layout is invalidated and before requerying the layout information.
    Subclasses should always call super if they override.
 */
- (void)prepareLayout {

    [super prepareLayout];

    [self.layoutInfoArray removeAllObjects];

    [self.itemLayoutInfoArray removeAllObjects];

    NSInteger numberOfSection = [self.collectionView numberOfSections];

    for (int section = 0; section < numberOfSection; section ++) {

        NSInteger numberOfItems = [self.collectionView numberOfItemsInSection:section];

        NSMutableArray *tmp_layoutArray = [NSMutableArray array];

        NSMutableArray *tmp_itemArray = [NSMutableArray array];

        if (section == 2 && numberOfItems > 0) {

            UICollectionViewLayoutAttributes *headerAttr = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForRow:0 inSection:section]];

            [tmp_layoutArray addObject:headerAttr];
        }

        for (int item = 0; item < numberOfItems; item ++) {

            NSIndexPath *indexPath = [NSIndexPath indexPathForRow:item inSection:section];

            UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:indexPath];

            [tmp_layoutArray addObject:attributes];

            [tmp_itemArray addObject:attributes];
        }

        if (section == 3 && numberOfItems > 0) {

            UICollectionViewLayoutAttributes *footerAttr = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionFooter atIndexPath:[NSIndexPath indexPathForRow:0 inSection:section]];

            [tmp_layoutArray addObject:footerAttr];
        }

        // 把每一个section的每一个item的布局信息添加数组
        if (tmp_layoutArray.count > 0) {

            [self.layoutInfoArray addObject:tmp_layoutArray];
        }

        if (tmp_itemArray.count > 0) {

            [self.itemLayoutInfoArray addObject:tmp_itemArray];
        }
    }

    UICollectionViewLayoutAttributes *attri = [[self.layoutInfoArray lastObject] lastObject];

    self.contentSize = CGSizeMake(_width_, CGRectGetMaxY(attri.frame));
}

/** 
    Subclasses must override this method and use it to return the width and height of the collection view’s content. These values represent the width and height of all the content, not just the content that is currently visible. The collection view uses this information to configure its own content size to facilitate scrolling.
 */
- (CGSize)collectionViewContentSize {

    return self.contentSize;
}

/**
 Returns the layout information for the item at the specified index path.

 This method updates the layout information as needed before returning the specified attributes. Always use this method to retrieve the layout attributes for items in the collection view. Do not query the layout object directly.
 */
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {

    UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];

    if (indexPath.section == 0) {

        attributes.frame = CGRectMake(0, 0, _width_, 44);

    } else if (indexPath.section == 1) {

        NSInteger row = indexPath.row;

        CGFloat margin_x = 5;

        CGFloat margin_y = 5;

        CGFloat item_w = (_width_ - 4 * margin_x) / 3;

        CGFloat item_h = item_w;

        CGFloat item_x = margin_x + (item_w + margin_x) * (row % 3);

        CGFloat item_y = 44 + 10 + (item_h + margin_y) * (row / 3);

        attributes.frame = CGRectMake(item_x, item_y, item_w, item_h);

    } else if (indexPath.section == 2) {

        UICollectionViewLayoutAttributes *attributesTmp = [[self.itemLayoutInfoArray lastObject] lastObject];

        CGFloat item_y = CGRectGetMaxY(attributesTmp.frame) + 44;

        attributes.frame = CGRectMake(0, item_y, _width_, 44);

    } else if (indexPath.section == 3) {

        UICollectionViewLayoutAttributes *attributesTmp = [[self.itemLayoutInfoArray lastObject] lastObject];

        CGFloat item_h = 44;

        CGFloat item_y = CGRectGetMaxY(attributesTmp.frame) + 10 + item_h * indexPath.row;

        attributes.frame = CGRectMake(0, item_y, _width_, item_h);

    }
    
    return attributes;
}

- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath {

    NSInteger numberOfItems = [self.collectionView numberOfItemsInSection:indexPath.section];

    if (elementKind == UICollectionElementKindSectionHeader) {

        UICollectionViewLayoutAttributes *header_attributes = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader withIndexPath:indexPath];

        if (indexPath.section == 2 && numberOfItems > 0) {

            header_attributes = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader withIndexPath:indexPath];

            UICollectionViewLayoutAttributes *attributesTmp = [[self.itemLayoutInfoArray lastObject] lastObject];

            CGFloat item_y = CGRectGetMaxY(attributesTmp.frame) + 5;

            header_attributes.frame = CGRectMake(0, item_y, _width_, 44);
            
        }

        return header_attributes;

    } else {

        UICollectionViewLayoutAttributes *footer_attributes = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionFooter withIndexPath:indexPath];

        if (indexPath.section == 3 && numberOfItems > 0) {

            footer_attributes = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionFooter withIndexPath:indexPath];

            UICollectionViewLayoutAttributes *attributesTmp = [[self.itemLayoutInfoArray lastObject] lastObject];

            NSInteger num_3 = [self.collectionView numberOfItemsInSection:3];

            CGFloat item_h = 44;

            CGFloat item_y = CGRectGetMaxY(attributesTmp.frame) + 10 + item_h * num_3;
            
            footer_attributes.frame = CGRectMake(0, item_y, _width_, 95);
            
        }

        return footer_attributes;
    }
}

/** 
    return an array layout attributes instances for all the views in the given rect
 */
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {

    NSMutableArray *layoutAttributesArr = [NSMutableArray array];

    for (NSMutableArray *array in self.layoutInfoArray) {

        for (UICollectionViewLayoutAttributes *attributes in array) {

            [layoutAttributesArr addObject:attributes];
        }
    }

    return layoutAttributesArr;
}
@end

 不定期更新 不合适的地方 还请指点~ 感激不尽
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容