iOS自定义UICollectionViewLayout布局实现瀑布流

自定义 UICollectionViewLayout 布局,实现瀑布流;UICollectionView和UICollectionViewCell 另行创建,这只是布局文件, 外界控制器只要遵守协议并成为他的代理并实现代理方法heightForItemAtIndex:返回每个cell的高就可以实现温布流效果,也 可以实现相应的代理方法设置总共有多少列或是行间距列间距与边框间距。
 

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

猜你喜欢

转载自blog.csdn.net/cybtop/article/details/76696758