iOS自定义UICollectionViewLayout布局实现瀑布流
ViewLayout.h 文件:
#import <UIKit/UIKit.h>
@class ViewLayout;
@protocol ViewLayoutDelegate <NSObject>
// 必须要实现的方法
@required
/** 返回 index位置的item的高 */
- (CGFloat)viewLayout:(ViewLayout *)ViewLayout heightForItemAtIndex:(NSInteger)index width:(CGFloat)width;
// 可选实现的方法
@optional
/** 返回 ViewLayout布局的最大例数 */
- (CGFloat)numberOfMaxColumnInViewLayout:(ViewLayout *)viewLayout;
/** 返回 ViewLayout布局每列的间距 */
- (CGFloat)numberOfColumnMarginInViewLayout:(ViewLayout *)viewLayout;
/** 返回 ViewLayout布局的行间距 */
- (CGFloat)numberOfRowMarginInViewLayout:(ViewLayout *)viewLayout;
/** 返回 ViewLayout布局的上左下右边框间距 */
- (UIEdgeInsets)edgeInsetsOfEdgeInViewLayout:(ViewLayout *)viewLayout;
@end
@interface ViewLayout :UICollectionViewLayout
/** ViewLayout 代理属性 */
@property (nonatomic,weak) id <ViewLayoutDelegate> delegate;
@end
ViewLayout.m 文件:
#import "ViewLayout.h"
/** 默认最大例数 */
static constNSInteger defaultMaxColumn =3;
/** 默认例间距 */
static constCGFloat defaultdefaultColumnMargin =10;
/** 默认行间距 */
static constCGFloat defaultdefaultRowMargin =10;
/** 默认边框间距 */
static constUIEdgeInsets defaultEdgeInsets = {10,10 ,10,10};
@interface ViewLayout ()
/** 装有所有的布局性的数组 */
@property (nonatomic,strong) NSMutableArray *attributesArray;
/** 装有所有有例的高度 */
@property (nonatomic,strong) NSMutableArray *columnHeights;
//方法声明
- (CGFloat)maxColumn;
- (CGFloat)columnMargin;
- (CGFloat)rowMargin;
- (UIEdgeInsets)edgeInsets;
@end
@implementation ViewLayout
/** 返回最大列数方法实现*/
- (CGFloat)maxColumn{
if ([self.delegaterespondsToSelector:@selector(numberOfMaxColumnInViewLayout:)]) {
return [self.delegatenumberOfMaxColumnInViewLayout:self];
}else{
returndefaultMaxColumn;
}
}
/** 返回列间距方法实现*/
- (CGFloat)columnMargin{
if ([self.delegaterespondsToSelector:@selector(numberOfColumnMarginInViewLayout:)]) {
return [self.delegatenumberOfColumnMarginInViewLayout:self];
}else{
returndefaultdefaultColumnMargin;
}
}
/** 行间距方法实现*/
- (CGFloat)rowMargin{
if ([self.delegaterespondsToSelector:@selector(numberOfRowMarginInViewLayout:)]) {
return [self.delegatenumberOfRowMarginInViewLayout:self];
}else{
returndefaultdefaultRowMargin;
}
}
/** 边框的间距方法实现*/
- (UIEdgeInsets)edgeInsets{
if ([self.delegaterespondsToSelector:@selector(edgeInsetsOfEdgeInViewLayout:)]) {
return [self.delegateedgeInsetsOfEdgeInViewLayout:self];
}else{
returndefaultEdgeInsets;
}
}
- (NSMutableArray *)attributesArray{
if (!_attributesArray) {
_attributesArray = [NSMutableArrayarray];
}
return_attributesArray;
}
- (NSMutableArray *)columnHeights{
if (!_columnHeights) {
_columnHeights = [NSMutableArrayarray];
}
return_columnHeights;
}
// 准备开始布局时调用方法
- (void)prepareLayout{
[superprepareLayout];
[self.columnHeightsremoveAllObjects];
[self.attributesArrayremoveAllObjects];
//先初始给装有所有例高数组赋值
for (int i =0; i < self.maxColumn; ++i) {
self.columnHeights[i] =@(self.edgeInsets.top);
}
//获取第总共的cell数量
NSInteger count = [self.collectionViewnumberOfItemsInSection:0];
//有 for循环为每为个 cell添加布局属性
for (int i =0; i < count; ++i) {
//创建第 i个位置索引
NSIndexPath *indexPath = [NSIndexPathindexPathForItem:i inSection:0];
//根据索引创建布局属性
UICollectionViewLayoutAttributes *attributes = [selflayoutAttributesForItemAtIndexPath:indexPath];
[self.attributesArrayaddObject:attributes];
}
}
// 返回所有元素的布局属性数组
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{
returnself.attributesArray;
}
// 返回索引 indexPath位置的cell的布属性
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributeslayoutAttributesForCellWithIndexPath:indexPath];
CGFloat width =self.collectionView.bounds.size.width;
CGFloat w = (width -self.edgeInsets.left -self.edgeInsets.right - ((self.maxColumn - 1) * self.columnMargin)) /self.maxColumn;
// 执行代理方法拿到代理方法返回的高度
CGFloat h = [self.delegateviewLayout:selfheightForItemAtIndex:indexPath.itemwidth:w];
// 找出最短的那一例的高和例号
CGFloat miniHeight = [self.columnHeights[0]doubleValue]; //先初始默认数组中第0个元素最小值
NSInteger miniColumn =0; //初始默认最小例号
for (int i =1; i < self.maxColumn; ++i) {
CGFloat height = [self.columnHeights[i]doubleValue];
if (miniHeight > height) {
miniHeight = height;
miniColumn = i;
}
}
CGFloat x =self.edgeInsets.left + miniColumn * (w +self.columnMargin);
CGFloat y = miniHeight;
if (y !=self.edgeInsets.top) {
y += self.rowMargin;
}
attributes.frame =CGRectMake(x, y, w, h);
//保存更新当前高到对应例的数组
self.columnHeights[miniColumn] =@(CGRectGetMaxY(attributes.frame));
return attributes;
}
// collectionView的滚动范围
- (CGSize)collectionViewContentSize{
//找出最高的所在例
CGFloat maxHeight =0; //初始最大高为 0
for (int i =0; i < self.maxColumn; ++i) {
CGFloat height = [self.columnHeights[i]doubleValue];
if (maxHeight < height) {
maxHeight = height;
}
}
returnCGSizeMake(0, maxHeight +self.edgeInsets.bottom);
}
@end