iOS瀑布流布局实现

最近开发中遇到了关于瀑布流布局的需求,所有就整理了一个瀑布流布局类,使用时只需要调整列数、行间距、列间距、上下左右边缘就可以做出各种需求的瀑布流布局,下面直接上代码:

自定义瀑布流需要继承UICollectionViewLayout布局类

.h文件


#import <UIKit/UIKit.h>


@interface ZYYWaterLayout :UICollectionViewLayout


@end


.m文件

#import "ZYYWaterLayout.h"

//默认的列数

staticconst CGFloat ZYYCollumCoutnt =3;

//列间距

staticconst CGFloat ZYYCollumMargin =10;

//行间距

staticconst CGFloat ZYYRowMargin =10;

//边缘间距

staticconst UIEdgeInsets ZYYEdgeUnsets = {10,10,10,10};


@interfaceZYYWaterLayout()


//用于存放cell属性的数组

@property (strong,nonatomic)NSMutableArray *attrsArray;

//用于存放所有列高度数组

@property (strong,nonatomic)NSMutableArray *maxH;


@end


@implementation ZYYWaterLayout


//懒加载属性数组

- (NSMutableArray *)attrsArray{

    if (_attrsArray ==nil) {

        _attrsArray = [NSMutableArrayarray];

        

    }

    return_attrsArray;

}


//懒加载高度属性数组

- (NSMutableArray *)maxH{

    if (_maxH ==nil) {

        _maxH = [NSMutableArrayarray];

        

    }

    return_maxH;

}



//准备布局每次刷新都会调用此方法

- (void)prepareLayout{

    [superprepareLayout];

    

   //先清除以前计算的所有高度,这种做法比较严谨,如果有下拉刷新,不及时清空数组的话会造成数据混乱

    [self.maxHremoveAllObjects];

    

   //这里先将数组里面的初始值设为0

    for (NSInteger i =0; i < ZYYCollumCoutnt; i ++) {

        [self.maxHaddObject:@0];

    }


     NSLog(@"%s",__func__);

   //清除以前的所有属性

    [self.attrsArrayremoveAllObjects];


   //开始创建每个cell对应的布局属性

    //1、获取collectionView里面的有多少个item

    NSInteger count = [self.collectionViewnumberOfItemsInSection:0];

    

    //创建多少collectionViewcell属性

    for (NSInteger i=1; i<count; i++) {

        //获取item对应的indexPath

        NSIndexPath *indexPath = [NSIndexPathindexPathForItem:i inSection:0];

        

        //创建属性调用下面的layoutAttributesForItemAtIndexPath方法

        UICollectionViewLayoutAttributes *attrs = [selflayoutAttributesForItemAtIndexPath:indexPath];

        //设置cell的属性直接调用layoutAttributesForItemAtIndexPath方法即可

        

        [self.attrsArrayaddObject:attrs];

    }

    

}


/**

 * 决定布局的关键所在

 *

 *  @param rect 属性rect

 *

 *  @return 返回属性数组

 */

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{

    

    NSLog(@"%s",__func__);


    returnself.attrsArray;

}


/**

 *  返回indexPath位置cell对应的布局属性

 * 这个方法是核心算法

 */

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{

    //创建属性

    UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributeslayoutAttributesForCellWithIndexPath:indexPath];

    

    //collectionView的宽度

    CGFloat collectionViewW =self.collectionView.frame.size.width;

    

    //列号

    NSInteger cloumIndex =0;

   //默认第一行是最小的,这样做的话可以让下面的for循环从i=1开始遍历,这样做可以优化性能

    CGFloat minClumnHeight = [self.maxH[0]doubleValue];

    

    for (NSInteger i =1; i < ZYYCollumCoutnt; i++) {

        //取出第i列元素的y

        CGFloat cheight = [self.maxH[i]doubleValue];

        if (minClumnHeight > cheight) {

            minClumnHeight = cheight;

            cloumIndex = i;

        }

    }

    

    //每个item的宽度 == collectionView的宽度 -左边距 -右边距 -(列数-1*间距)再除于列数

    CGFloat w = (collectionViewW -ZYYEdgeUnsets.left -ZYYEdgeUnsets.right - (ZYYCollumCoutnt -1) * ZYYCollumMargin)/3.0;

    

   //高度这里用的是随机数,做项目时根据的是素材的高度

    CGFloat h =50 + arc4random_uniform(100);

    

    //x可以根据列来算

    CGFloat x =ZYYEdgeUnsets.left + cloumIndex * (ZYYRowMargin + w);


    //y最小itme值计算

    CGFloat y = minClumnHeight +ZYYRowMargin;

 

    //设置布局属性的frame,这个frame是最终itemframe

     attrs.frame =CGRectMake(x, y, w, h);


   //更新最短那列的高度

    self.maxH[cloumIndex] =@(CGRectGetMaxY(attrs.frame));

    

    return attrs;

}


//尺寸

- (CGSize)collectionViewContentSize{

    

   //找出y值最大的的那一列,和上面找出最小高度相似

    CGFloat maxColunmHeight = [self.maxH[0]doubleValue];

    for (NSInteger i =1; i < ZYYCollumCoutnt; i++) {

        CGFloat my = [self.maxH[i]doubleValue];

        if (maxColunmHeight < my) {

            maxColunmHeight = my;

        }

    }

    

    returnCGSizeMake(0, maxColunmHeight +ZYYEdgeUnsets.bottom);

}


结语:上面的注释比较清楚,用的时候直接将代码复制粘贴就可以使用了


@end



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值