效果如图:
自定义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
不定期更新 不合适的地方 还请指点~ 感激不尽