iOS学习笔记--瀑布流封装

最近学习了瀑布流布局,是用collectionView实现的。首先说说设计思路,用collectionView做出来的瀑布流是固定行数或者列数的。以现在主流固定列数为例,每个item就是固定宽,不固定高,同时每个item之间的间距是固定的,那么每行的Y值计算就需要通过前一行的最短的item来确定。

既然是用collectionView实现,而collectionView的布局是通过他的layout来实现,那么就需要重写UICollectionViewLayout中的

-(void)prepareLayout,

-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect,

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

-(CGSize)collectionViewContentSize

具体实现如下:

#import <UIKit/UIKit.h>


@class CustomWaterflowLayout;

@protocol CustomWaterflowLayoutDelegate <NSObject>

@required
//必须实现的代理方法,返回每个item的高度
-(CGFloat)customWaterflow:(CustomWaterflowLayout *)layout heightForItemAtIndexPath:(NSInteger)index itemWidth:(CGFloat)itemWidth;

@optional
-(NSInteger)colCountInCustomWaterflow:(CustomWaterflowLayout *)layout;
-(CGFloat)colMarginInCustomWaterflow:(CustomWaterflowLayout *)layout;
-(CGFloat)rowMarginInCustomWaterflow:(CustomWaterflowLayout *)layout;
-(UIEdgeInsets)edgeInsetsInCustomWaterflow:(CustomWaterflowLayout *)layout;

@end

@interface CustomWaterflowLayout : UICollectionViewLayout
@property (nonatomic, weak) id<CustomWaterflowLayoutDelegate>delegate;
@end

#import "CustomWaterflowLayout.h"

//默认列数
static const NSInteger CustomDefaultColumnCount = 3;
//每一列之间的间距
static const CGFloat CustomDefaultColMargin = 10.0;
//每一行之间的间距
static const CGFloat CustomDefaultRowMargin = 10.0;
//边缘间距
static const UIEdgeInsets CustomDefaultEdgeInsets = {10,10,10,10};

@interface CustomWaterflowLayout ()
//存放所有cell的布局属性
@property (nonatomic, strong) NSMutableArray * attributesAarray;
//存放所有列的当前高度
@property (nonatomic, strong) NSMutableArray * colHeightArray;
//内容的高度
@property (nonatomic, assign) CGFloat contentHeight;

-(CGFloat)colMargin;
-(CGFloat)rowMargin;
-(NSInteger)colCount;
-(UIEdgeInsets)edgeInsets;
@end
@implementation CustomWaterflowLayout

#pragma mark 代理方法数据处理/常见数据处理
//这样写可以在代理方法中设置需要的布局数据,也可以有默认数据,是模仿tableView的代理实现
-(UIEdgeInsets)edgeInsets{
    if ([self.delegate respondsToSelector:@selector(edgeInsetsInCustomWaterflow:)]) {
        return [self.delegate edgeInsetsInCustomWaterflow:self];
    }else{
        return CustomDefaultEdgeInsets;
    }
}

-(NSInteger)colCount{
    if ([self.delegate respondsToSelector:@selector(colCountInCustomWaterflow:)]) {
        return [self.delegate colCountInCustomWaterflow:self];
    }else{
        return CustomDefaultColumnCount;
    }
}

-(CGFloat)colMargin{
    if ([self.delegate respondsToSelector:@selector(colMarginInCustomWaterflow:)]) {
        return [self.delegate colMarginInCustomWaterflow:self];
    }else{
        return CustomDefaultColMargin;
    }
}

-(CGFloat)rowMargin{
    if ([self.delegate respondsToSelector:@selector(rowMarginInCustomWaterflow:)]) {
        return [self.delegate rowMarginInCustomWaterflow:self];
    }else{
        return CustomDefaultRowMargin;
    }
}

//懒加载
-(NSMutableArray *)colHeightArray{
    if (!_colHeightArray) {
        _colHeightArray = [NSMutableArray array];
    }
    return _colHeightArray;
}

-(NSMutableArray *)attributesAarray{
    //创建一个数组(存放所有cell的布局属性)
    if (!_attributesAarray) {
        _attributesAarray = [NSMutableArray array];
    }
    return _attributesAarray;
}

//初始化
-(void)prepareLayout{
    [super prepareLayout];
    
    self.contentHeight = 0;
    
    //清除以前计算的所有高度
    [self.colHeightArray removeAllObjects];
    for (NSInteger i = 0; i < self.colCount; i++) {
        [self.colHeightArray addObject:@(self.edgeInsets.top)];
    }
    
    //清空之前所有的布局属性
    [self.attributesAarray removeAllObjects];
    
    //开始创建每一个cell对应的布局属性
    NSInteger count = [self.collectionView numberOfItemsInSection:0];
    for (NSInteger i = 0; i < count; i++) {
        //创建位置
        NSIndexPath * indexPath = [NSIndexPath indexPathForItem:i inSection:0];
        
        //获取indexPath位置cell的对应的布局属性
        UICollectionViewLayoutAttributes * attrs = [self layoutAttributesForItemAtIndexPath:indexPath];
        
        [self.attributesAarray addObject:attrs];
    }
}

//决定cell的排布
-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{
 
    return self.attributesAarray;
}

//返回indexPath位置cell对应的布局属性
-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
    
    //创建布局属性
    UICollectionViewLayoutAttributes * attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    
    
    //collectionView的宽度
    CGFloat collectionWidth = self.collectionView.frame.size.width;
    
    //设置布局属性的frame
    CGFloat w = (collectionWidth - self.edgeInsets.left - self.edgeInsets.right - (self.colCount - 1) * self.colMargin) / self.colCount;
    CGFloat h = [self.delegate customWaterflow:self heightForItemAtIndexPath:indexPath.item itemWidth:w];
    
    NSInteger destCol = 0;
    CGFloat minColHeight = [self.colHeightArray[0] doubleValue];
    for (NSInteger i = 1; i < self.colCount; i++) {
        CGFloat colHeight = [self.colHeightArray[i] doubleValue];
        
        if (minColHeight > colHeight) {
            minColHeight = colHeight;
            destCol = i;
        }
    }
    
    CGFloat x = self.edgeInsets.left + destCol * (self.colMargin + w);
    
    CGFloat y = minColHeight;
    if (y != self.edgeInsets.top) {
        //非第一行
        y += self.rowMargin;
        
    }
    attrs.frame = CGRectMake(x,y,w,h);
    
    //更新最短那列的高度
    self.colHeightArray[destCol] = @(CGRectGetMaxY(attrs.frame));
    
    CGFloat colHeight = [self.colHeightArray[destCol] doubleValue];
    if (self.contentHeight < colHeight) {
        self.contentHeight = colHeight;
    }
    
    return attrs;
}

-(CGSize)collectionViewContentSize{
    
    return CGSizeMake(0, self.contentHeight + self.edgeInsets.bottom);
}

@end







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值