iOS UICollectionView之瀑布流

瀑布流的实现
实现一个自定义的瀑布流UICollectionViewLayout的常规做法是继承UICollectionViewLayout,然后重载下列方法

// 布局计算
-(void)prepareLayout
// 返回collectionView的内容尺寸
-(CGSize)collectionViewContentSize
/**
 *  返回rect中的所有元素的布局属性
 *  返回的是包含UICollectionViewLayoutAttributes的数组
 *  UICollectionViewLayoutAttributes可以是cell、SupplementaryView或者DecorationView的信息通过不同的UICollectionViewLayoutAttributes初始化方法可以得到不同类型的UICollectionViewLayoutAttributes
 *  + (instancetype)layoutAttributesForCellWithIndexPath:(NSIndexPath *)indexPath
 *  + (instancetype)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind withIndexPath:(NSIndexPath *)indexPath
 *  + (instancetype)layoutAttributesForDecorationViewOfKind:(NSString *)decorationViewKind withIndexPath:(NSIndexPath *)indexPath
 */
-(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect
// 返回对应于indexPath的位置的cell的布局属性
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)path
// 返回对应于indexPath位置的SupplementaryView的布局属性,如果没有SupplementaryView可不重载
- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath;
//  返回对应于indexPath位置的DecorationView的布局属性,如果没有DecorationView可不重载
- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForDecorationViewOfKind:(NSString*)elementKind atIndexPath:(NSIndexPath *)indexPath;

DMWaterfallFlowLayout.h

#import 

@class DMWaterfallFlowLayout;

@protocol DMWaterfallFlowLayoutDelegate 

@required
/**
 *  cell 高度
 */
- (CGFloat)waterfallFlowLayout:(DMWaterfallFlowLayout *)waterfallFlowLayout heightForItemAtIndexPath:(NSIndexPath *)indexPath itemWidth:(CGFloat)width;

@optional
/**
 * 分区 sectionHeader 高度
 */
- (CGFloat)waterfallFlowLayout:(DMWaterfallFlowLayout *)waterfallFlowLayout heightForHeaderInSection:(NSInteger)section;

/**
 * 分区 sectionFooter 高度
 */
- (CGFloat)waterfallFlowLayout:(DMWaterfallFlowLayout *)waterfallFlowLayout heightForFooterInSection:(NSInteger)section;

/**
 *  分区 列数
 */
- (NSInteger)waterfallFlowLayout:(DMWaterfallFlowLayout *)waterfallFlowLayout columnCountInSection:(NSInteger)section;

/**
 *  分区 列间距
 */
- (CGFloat)waterfallFlowLayout:(DMWaterfallFlowLayout *)waterfallFlowLayout columnMarginInSection:(NSInteger)section;

/**
 *  分区 行间距
 */
- (CGFloat)waterfallFlowLayout:(DMWaterfallFlowLayout *)waterfallFlowLayout rowMarginInSection:(NSInteger)section;

/**
 *  分区 UIEdgeInsets
 */
- (UIEdgeInsets)waterfallFlowLayout:(DMWaterfallFlowLayout *)waterfallFlowLayout edgeInsetsInSection:(NSInteger)section;

@end

@interface DMWaterfallFlowLayout : UICollectionViewFlowLayout

@property (nonatomic, weak) id delegate;

- (CGFloat)headerHeightInSection:(NSInteger)section;

- (CGFloat)footerHeightInSection:(NSInteger)section;

- (NSInteger)columnCountInSection:(NSInteger)section;

- (CGFloat)columnMarginInSection:(NSInteger)section;

- (CGFloat)rowMarginInSection:(NSInteger)section;

- (UIEdgeInsets)edgeInsetsInSection:(NSInteger)section;

@end

DMWaterfallFlowLayout.m

#import "DMWaterfallFlowLayout.h"

/** section Header 高度 */
static const CGFloat DMDefaultHeaderHeight = 0;

/** section Footer 高度 */
static const CGFloat DMDefaultFooterHeight = 0;

/** 列数 */
static const NSInteger DMDefaultColumCount = 2;

/** 每一列间距 */
static const CGFloat DMDefaultColumMargin = 10;

/** 每一行间距 */
static const CGFloat DMDefaultRowMargin = 10;

/** 边缘间距 */
static const UIEdgeInsets DMDefaultEdgeInsets = {10,0,10,0};


@interface DMWaterfallFlowLayout ()

/** 布局属性数组 */
@property (nonatomic, strong) NSMutableArray *attrsArray;

/** 存放section数组,每一个section数组中存放列的当前高度 */
@property (nonatomic, strong) NSMutableArray *columnHeightArray;

@end

@implementation DMWaterfallFlowLayout

#pragma mark - life cycle
- (void)prepareLayout
{
    [super prepareLayout];
    
    //如果刷新布局就会重新调用prepareLayout这个方法,所以要先把高度数组清空
    [self.columnHeightArray removeAllObjects];
    [self.attrsArray removeAllObjects];
    
    NSInteger sectionNum = [self.collectionView numberOfSections];
    for (NSInteger sectionIndex = 0; sectionIndex < sectionNum; sectionIndex++) {
        // 获取前一个section的高度
        CGFloat tmpBottom = 0;
        if (sectionIndex != 0) {
            NSArray *beforeColumnHeightArray = [self.columnHeightArray objectAtIndex:sectionIndex - 1];
            for (NSNumber *curNum in beforeColumnHeightArray) {
                if (tmpBottom < [curNum floatValue]) {
                    tmpBottom = [curNum floatValue];
                }
            }
        }
        
        // 1.先判断是否存在section Header
        CGFloat headerHeight = [self headerHeightInSection:sectionIndex];
        if (headerHeight > 0) {
            //获取UICollectionElementKindSectionHeader对应的布局属性
            NSIndexPath *curIndexPath = [NSIndexPath indexPathForRow:0 inSection:sectionIndex];
            UICollectionViewLayoutAttributes *layoutHeader = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:curIndexPath];
            [self.attrsArray addObject:layoutHeader];
        }
        
        // section edge inset
        UIEdgeInsets sectionEdgeInsets = [self edgeInsetsInSection:sectionIndex];
        
        // cell
        NSInteger tmpColumnCount = [self columnCountInSection:sectionIndex];
        NSMutableArray *tmpColumnHeightArray = [[NSMutableArray alloc] init];
        for (NSInteger columnIndex = 0; columnIndex < tmpColumnCount; columnIndex++) {
            [tmpColumnHeightArray addObject:[NSNumber numberWithFloat:tmpBottom + headerHeight + sectionEdgeInsets.top]];
        }
        
        [self.columnHeightArray addObject:tmpColumnHeightArray];
        NSInteger itemsNum = [self.collectionView numberOfItemsInSection:sectionIndex];
        for (NSInteger itemIndex = 0; itemIndex < itemsNum; itemIndex++) {
            NSIndexPath *indexPath = [NSIndexPath indexPathForRow:itemIndex inSection:sectionIndex];
            //获取indexPath 对应cell 的布局属性
            UICollectionViewLayoutAttributes *attr = [self layoutAttributesForItemAtIndexPath:indexPath];
            [self.attrsArray addObject:attr];
        }
        
        if (sectionEdgeInsets.bottom > 0) {
            for (NSInteger columnIndex = 0; columnIndex < tmpColumnCount; columnIndex++) {
                // 更新数组中列的当前高度
                NSNumber *curHeight = tmpColumnHeightArray[columnIndex];
                tmpColumnHeightArray[columnIndex] = [NSNumber numberWithFloat:curHeight.doubleValue + sectionEdgeInsets.bottom];
            }
        }
        
        // section Footer
        CGFloat footerHeight = [self footerHeightInSection:sectionIndex];
        if (footerHeight > 0) {
            //获取UICollectionElementKindSectionFooter对应的布局属性
            NSIndexPath *curIndexPath = [NSIndexPath indexPathForRow:0 inSection:sectionIndex];
            UICollectionViewLayoutAttributes *layoutFooter = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionFooter atIndexPath:curIndexPath];
            [self.attrsArray addObject:layoutFooter];
            for (NSInteger columnIndex = 0; columnIndex < tmpColumnCount; columnIndex++) {
                // 更新数组中列的当前高度
                NSNumber *curHeight = tmpColumnHeightArray[columnIndex];
                tmpColumnHeightArray[columnIndex] = [NSNumber numberWithFloat:curHeight.doubleValue + footerHeight];
            }
        }
    }
}

/**
 *  返回supplementaryView对应的布局属性
 */
- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewLayoutAttributes *tempAttr = nil;
    if ([elementKind isEqualToString:UICollectionElementKindSectionHeader]) {
        UICollectionViewLayoutAttributes *attr = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:elementKind withIndexPath:indexPath];
        NSInteger sectionIndex = indexPath.section;
        CGFloat headerOriginY = 0;
        // 前一个section的高度
        if (sectionIndex != 0) {
            NSArray *beforeColumnHeightArray = [self.columnHeightArray objectAtIndex:sectionIndex - 1];
            for (NSNumber *curNum in beforeColumnHeightArray) {
                if (headerOriginY < [curNum floatValue]) {
                    headerOriginY = [curNum floatValue];
                }
            }
        }
        
        CGFloat headerHeight = [self headerHeightInSection:sectionIndex];
        // 设置frame
        attr.frame = CGRectMake(0, headerOriginY, [UIScreen mainScreen].bounds.size.width, headerHeight);
        tempAttr = attr;
    } else if ([elementKind isEqualToString:UICollectionElementKindSectionFooter]) {
        NSInteger sectionIndex = indexPath.section;
        CGFloat footerOriginY = 0;
        NSArray *curColumnHeightArray = [self.columnHeightArray objectAtIndex:sectionIndex];
        for (NSNumber *curNum in curColumnHeightArray) {
            if (footerOriginY < [curNum floatValue]) {
                footerOriginY = [curNum floatValue];
            }
        }
        
        UICollectionViewLayoutAttributes *layoutFooter = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionFooter withIndexPath:indexPath];
        CGFloat footerHeight = [self footerHeightInSection:sectionIndex];
        // 设置frame
        layoutFooter.frame = CGRectMake(0, footerOriginY, [UIScreen mainScreen].bounds.size.width, footerHeight);
        
        tempAttr = layoutFooter;
    }
    
    return tempAttr;
}

/**
 *  返回indexPath 位置cell对应的布局属性
 */
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewLayoutAttributes *attr = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    
    NSInteger sectionIndex = indexPath.section;
    NSMutableArray *curColumnHeightArray =  [self.columnHeightArray objectAtIndex:sectionIndex];
    
    // 获取前一个section的高度
    CGFloat tmpBottom = 0;
    if (sectionIndex != 0) {
        NSArray *beforeColumnHeightArray = [self.columnHeightArray objectAtIndex:sectionIndex - 1];
        for (NSNumber *curNum in beforeColumnHeightArray) {
            if (tmpBottom < [curNum floatValue]) {
                tmpBottom = [curNum floatValue];
            }
        }
    }
    
    // 当前section的section header
    CGFloat headerHeight = [self headerHeightInSection:sectionIndex];
    if (headerHeight > 0) {
        tmpBottom += headerHeight;
    }
    
    // section edge inset
    UIEdgeInsets sectionEdgeInsets = [self edgeInsetsInSection:sectionIndex];
    
    CGFloat sectionColumnMargin =  [self columnMarginInSection:sectionIndex];
    CGFloat sectionRowMargin =  [self rowMarginInSection:sectionIndex];
    
    //使用for循环,找出高度最短的那一列
    //最短高度的列(即存放当前cell的列)
    NSInteger destColumn = 0;
    CGFloat minColumnHeight = [curColumnHeightArray[0] doubleValue];
    
    NSInteger tmpColumnCount = [self columnCountInSection:sectionIndex];
    for (NSInteger i = 1; i < tmpColumnCount; i++) {
        CGFloat columnHeight  = [curColumnHeightArray[i] doubleValue];
        if (minColumnHeight > columnHeight) {
            minColumnHeight = columnHeight;
            destColumn = I;
        }
    }
    
    //cell item的宽度
    CGFloat w = (self.collectionView.frame.size.width - sectionEdgeInsets.left - sectionEdgeInsets.right - (tmpColumnCount - 1) * sectionColumnMargin ) / tmpColumnCount;
    //cell item的高度
    CGFloat h = [self.delegate waterfallFlowLayout:self heightForItemAtIndexPath:indexPath itemWidth:w];
    //cell item的起点x
    CGFloat x = sectionEdgeInsets.left + destColumn * (w + sectionColumnMargin);
    //cell item的起点y
    CGFloat y = minColumnHeight ;
    
    // 当前cell不是分区的第一行cell 时 添加一个行Margin
    if (y != tmpBottom + sectionEdgeInsets.top) {
        y += sectionRowMargin;
    }
    
    // 设置frame
    attr.frame = CGRectMake(x,y,w,h);
    
    // 修改数组中当前列的高度
    curColumnHeightArray[destColumn] =  [NSNumber numberWithFloat:y+ h];
    
    return attr;
}

/**
 *  决定UICollectionView的排布
 */
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
    return self.attrsArray;
}

/**
 *  可滑动范围
 */
- (CGSize)collectionViewContentSize
{
    CGFloat maxHeight = 0;
    NSInteger sectionNum = [self.collectionView numberOfSections];
    
    if (sectionNum > 0) {
        NSArray *curColumnHeightArray = [self.columnHeightArray objectAtIndex:sectionNum - 1];
        for (NSNumber *curNum in curColumnHeightArray) {
            if (maxHeight < [curNum floatValue]) {
                maxHeight = [curNum floatValue];
            }
        }
    }
    
    return CGSizeMake(0, maxHeight);
}

#pragma mark - public method
- (CGFloat)headerHeightInSection:(NSInteger)section
{
    CGFloat tempHeaderHeight = 0;
    if (self.delegate && [self.delegate respondsToSelector:@selector(waterfallFlowLayout:heightForHeaderInSection:)]) {
        tempHeaderHeight = [self.delegate waterfallFlowLayout:self heightForHeaderInSection:section];
    } else {
        tempHeaderHeight = DMDefaultHeaderHeight;
    }
    
    return tempHeaderHeight;
}

- (CGFloat)footerHeightInSection:(NSInteger)section
{
    CGFloat tempHeaderHeight = 0;
    if (self.delegate && [self.delegate respondsToSelector:@selector(waterfallFlowLayout:heightForFooterInSection:)]) {
        tempHeaderHeight = [self.delegate waterfallFlowLayout:self heightForFooterInSection:section];
    } else {
        tempHeaderHeight = DMDefaultFooterHeight;
    }
    
    return tempHeaderHeight;
}

- (NSInteger)columnCountInSection:(NSInteger)section
{
    NSInteger tempColumn = 0;
    if (self.delegate && [self.delegate respondsToSelector:@selector(waterfallFlowLayout:columnCountInSection:)]) {
        tempColumn = [self.delegate waterfallFlowLayout:self columnCountInSection:section];
    } else {
        tempColumn = DMDefaultColumCount;
    }
    
    return tempColumn;
}

- (CGFloat)columnMarginInSection:(NSInteger)section
{
    CGFloat tempColumnMargin = 0;
    if (self.delegate && [self.delegate respondsToSelector:@selector(waterfallFlowLayout:columnMarginInSection:)]) {
        tempColumnMargin = [self.delegate waterfallFlowLayout:self columnMarginInSection:section];
    } else {
        tempColumnMargin = DMDefaultColumMargin;
    }
    
    return tempColumnMargin;
}

- (CGFloat)rowMarginInSection:(NSInteger)section
{
    CGFloat tempRowMargin = 0;
    if (self.delegate && [self.delegate respondsToSelector:@selector(waterfallFlowLayout:rowMarginInSection:)]) {
        tempRowMargin = [self.delegate waterfallFlowLayout:self rowMarginInSection:section];
    } else {
        tempRowMargin = DMDefaultRowMargin;
    }
    
    return tempRowMargin;
}

- (UIEdgeInsets)edgeInsetsInSection:(NSInteger)section
{
    UIEdgeInsets tempEdgeInset = UIEdgeInsetsZero;
    if (self.delegate && [self.delegate respondsToSelector:@selector(waterfallFlowLayout:edgeInsetsInSection:)]) {
        tempEdgeInset = [self.delegate waterfallFlowLayout:self edgeInsetsInSection:section];
    } else {
        tempEdgeInset = DMDefaultEdgeInsets;
    }
    
    return tempEdgeInset;
}

#pragma mark - getter and setter
- (NSMutableArray *)attrsArray
{
    if (_attrsArray == nil) {
        _attrsArray = [[NSMutableArray alloc] init];
    }
    
    return _attrsArray;
}

- (NSMutableArray *)columnHeightArray
{
    if (_columnHeightArray == nil) {
        _columnHeightArray = [[NSMutableArray alloc] init];
    }
    
    return _columnHeightArray;
}

@end

注释已经很详细了
看一下如何使用,实例如下

#import "DMFunctionWaterfallViewController.h"
#import "DMWaterfallFlowLayout.h"
#import "DMSectionHeaderCollectionReusableView.h"
#import "DMSectionFooterCollectionReusableView.h"
#import "DMNormalCollectionViewCell.h"
#import "DMWaterfallCollectionViewCell.h"

static NSString * const kDMSectionHeaderCollectionReusableViewIdentifier = @"kDMSectionHeaderCollectionReusableViewIdentifier";
static NSString * const kDMSectionFooterCollectionReusableViewIdentifier = @"kDMSectionFooterCollectionReusableViewIdentifier";
static NSString * const kDMNormalCollectionViewCellIdentifier = @"kDMNormalCollectionViewCellIdentifier";
static NSString * const kDMWaterfallCollectionViewCellIdentifier = @"kDMWaterfallCollectionViewCellIdentifier";

@interface DMFunctionWaterfallViewController () 

/** UI */
@property (nonatomic, strong) UICollectionView *myCollectionView;


/** DATA */
@property (nonatomic, strong) NSMutableArray *dataArray;

@end

@implementation DMFunctionWaterfallViewController

#pragma mark - life cycle
- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor whiteColor];
    self.title = @"瀑布流";
    [self initData];
    
    [self.view addSubview:self.myCollectionView];
}

- (void)initData
{
    {
        NSMutableArray *sectionOneArray = [[NSMutableArray alloc] init];
        {
            DMNormalCollectionViewCellModel *modelOne = [[DMNormalCollectionViewCellModel alloc] init];
            modelOne.imageName = @"picOne";
            [sectionOneArray addObject:modelOne];
        }
        {
            DMNormalCollectionViewCellModel *modelTwo = [[DMNormalCollectionViewCellModel alloc] init];
            modelTwo.imageName = @"picTow";
            [sectionOneArray addObject:modelTwo];
        }
        [self.dataArray addObject:sectionOneArray];
    }
    
    {
        NSMutableArray *sectionTwoArray = [[NSMutableArray alloc] init];
        {
            DMWaterfallCollectionViewCellModel *modelOne = [[DMWaterfallCollectionViewCellModel alloc] init];
            modelOne.imageName = @"YY1";
            modelOne.ratioNum = [NSNumber numberWithFloat:1/1.5];
            modelOne.numStr = @"1";
            [sectionTwoArray addObject:modelOne];
        }
        {
            DMWaterfallCollectionViewCellModel *modelTwo = [[DMWaterfallCollectionViewCellModel alloc] init];
            modelTwo.imageName = @"YY2";
            modelTwo.ratioNum = [NSNumber numberWithFloat:1.5/1.0];
            modelTwo.numStr = @"2";
            [sectionTwoArray addObject:modelTwo];
        }
        {
            DMWaterfallCollectionViewCellModel *modelThree = [[DMWaterfallCollectionViewCellModel alloc] init];
            modelThree.imageName = @"YY3";
            modelThree.ratioNum = [NSNumber numberWithFloat:1/1.6];
            modelThree.numStr = @"3";
            [sectionTwoArray addObject:modelThree];
        }
        {
            DMWaterfallCollectionViewCellModel *modelFour = [[DMWaterfallCollectionViewCellModel alloc] init];
            modelFour.imageName = @"YY4";
            modelFour.ratioNum = [NSNumber numberWithFloat:1/1.7];
            modelFour.numStr = @"4";
            [sectionTwoArray addObject:modelFour];
        }
        {
            DMWaterfallCollectionViewCellModel *modelThree = [[DMWaterfallCollectionViewCellModel alloc] init];
            modelThree.imageName = @"YY5";
            modelThree.ratioNum = [NSNumber numberWithFloat:1/1.8];
            modelThree.numStr = @"5";
            [sectionTwoArray addObject:modelThree];
        } 
        [self.dataArray addObject:sectionTwoArray];
    }
    
    {
        NSMutableArray *sectionThreeArray = [[NSMutableArray alloc] init];
        {
            DMNormalCollectionViewCellModel *modelOne = [[DMNormalCollectionViewCellModel alloc] init];
            modelOne.imageName = @"mountain1";
            [sectionThreeArray addObject:modelOne];
        }
        {
            DMNormalCollectionViewCellModel *modelTwo = [[DMNormalCollectionViewCellModel alloc] init];
            modelTwo.imageName = @"mountain2";
            [sectionThreeArray addObject:modelTwo];
        }
        {
            DMNormalCollectionViewCellModel *modelThree = [[DMNormalCollectionViewCellModel alloc] init];
            modelThree.imageName = @"mountain3";
            [sectionThreeArray addObject:modelThree];
        }
        {
            DMNormalCollectionViewCellModel *modelFour = [[DMNormalCollectionViewCellModel alloc] init];
            modelFour.imageName = @"mountain4";
            [sectionThreeArray addObject:modelFour];
        }
        [self.dataArray addObject:sectionThreeArray];
    }
}

#pragma mark - UICollectionViewDataSource method
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
    NSInteger sectionNum = 0;
    sectionNum = [self.dataArray count];
    
    return sectionNum;
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    NSInteger itemsNum = 0;
    NSArray *itemsArray = [self.dataArray objectAtIndex:section];
    itemsNum = [itemsArray count];
    
    return itemsNum;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewCell *cell = nil;
    NSInteger sectionIndex = indexPath.section;
    NSInteger rowIndex = indexPath.row;
    NSArray *tmpDataArray = [self.dataArray objectAtIndex:sectionIndex];
    if (sectionIndex == 0) {
        DMNormalCollectionViewCell * tmpCell = [collectionView dequeueReusableCellWithReuseIdentifier:kDMNormalCollectionViewCellIdentifier forIndexPath:indexPath];
        DMNormalCollectionViewCellModel *dataModel = [tmpDataArray objectAtIndex:rowIndex];
        [tmpCell setDataModel:dataModel];
        cell = tmpCell;
    } else if (sectionIndex == 1) {
        DMWaterfallCollectionViewCell *tmpCell = [collectionView dequeueReusableCellWithReuseIdentifier:kDMWaterfallCollectionViewCellIdentifier forIndexPath:indexPath];
        DMWaterfallCollectionViewCellModel *dataModel = [tmpDataArray objectAtIndex:rowIndex];
        [tmpCell setDataModel:dataModel];
        cell = tmpCell;
    } else {
        DMNormalCollectionViewCell * tmpCell = [collectionView dequeueReusableCellWithReuseIdentifier:kDMNormalCollectionViewCellIdentifier forIndexPath:indexPath];
        DMNormalCollectionViewCellModel *dataModel = [tmpDataArray objectAtIndex:rowIndex];
        [tmpCell setDataModel:dataModel];
        cell = tmpCell;
    }
    
    return cell;
}

- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
    UICollectionReusableView *tmpView = nil;
    NSInteger sectionIndex = indexPath.section;
    if (sectionIndex == 0) {
        if ([kind isEqualToString:UICollectionElementKindSectionHeader]) {
            DMSectionHeaderCollectionReusableView *headerView =  [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:kDMSectionHeaderCollectionReusableViewIdentifier forIndexPath:indexPath];
            [headerView updateStr:@"第一个分区头部"];
            headerView.backgroundColor = [UIColor redColor];
            tmpView = headerView;
        } else if ([kind isEqualToString:UICollectionElementKindSectionFooter]) {
            DMSectionHeaderCollectionReusableView *footerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:kDMSectionFooterCollectionReusableViewIdentifier forIndexPath:indexPath];
            [footerView updateStr:@"第一个分区尾部"];
            footerView.backgroundColor = [UIColor yellowColor];
            tmpView = footerView;
        }
    } else if (sectionIndex == 1) {
        if ([kind isEqualToString:UICollectionElementKindSectionHeader]) {
            DMSectionHeaderCollectionReusableView *headerView =  [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:kDMSectionHeaderCollectionReusableViewIdentifier forIndexPath:indexPath];
            [headerView updateStr:@"第二个分区头部"];
            headerView.backgroundColor = [UIColor greenColor];
            tmpView = headerView;
        } else if ([kind isEqualToString:UICollectionElementKindSectionFooter]) {
            DMSectionHeaderCollectionReusableView *footerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:kDMSectionFooterCollectionReusableViewIdentifier forIndexPath:indexPath];
            [footerView updateStr:@"第二个分区尾部"];
            footerView.backgroundColor = [UIColor purpleColor];
            tmpView = footerView;
        }
    }
    
    return tmpView;
}

#pragma mark - UICollectionViewDelegate method

#pragma mark - DMWaterfallFlowLayoutDelegate method
- (CGFloat)waterfallFlowLayout:(DMWaterfallFlowLayout *)waterfallFlowLayout heightForItemAtIndexPath:(NSIndexPath *)indexPath itemWidth:(CGFloat)width
{
    NSInteger sectionIndex = indexPath.section;
    CGFloat itemHeight = 0;
    if (sectionIndex == 0) {
        itemHeight = [DMNormalCollectionViewCell cellHeight];
    } else if (sectionIndex == 1) {
        NSInteger sectionIndex = indexPath.section;
        NSInteger rowIndex = indexPath.row;
        NSArray *tmpDataArray = [self.dataArray objectAtIndex:sectionIndex];
        DMWaterfallCollectionViewCellModel *dataModel = [tmpDataArray objectAtIndex:rowIndex];
        itemHeight = width / [dataModel.ratioNum floatValue];
    } else if (sectionIndex == 2) {
        itemHeight = [DMNormalCollectionViewCell cellHeight];
    }
    
    return itemHeight;
}

/**
 * sectionHeader 高度
 */
- (CGFloat)waterfallFlowLayout:(DMWaterfallFlowLayout *)waterfallFlowLayout heightForHeaderInSection:(NSInteger)section
{
    CGFloat headerHeight = 0;
    if (section == 0) {
        headerHeight = 60;
    } else if (section == 1) {
        headerHeight = 40;
    }
    
    return headerHeight;
}

/**
 * sectionFooter 高度
 */
- (CGFloat)waterfallFlowLayout:(DMWaterfallFlowLayout *)waterfallFlowLayout heightForFooterInSection:(NSInteger)section
{
    CGFloat footerHeight = 0;
    if (section == 0) {
        footerHeight = 50;
    } else if (section == 1) {
        footerHeight = 40;
    }
    
    return footerHeight;
}

/**
 *  列数
 */
- (NSInteger)waterfallFlowLayout:(DMWaterfallFlowLayout *)waterfallFlowLayout columnCountInSection:(NSInteger)section
{
    NSInteger columnCount = 0;
    if (section == 0) {
        columnCount = 1;
    } else if (section == 1) {
        columnCount = 2;
    } else {
        columnCount = 1;
    }
    
    return columnCount;
}

/**
 *  列间距
 */
- (CGFloat)waterfallFlowLayout:(DMWaterfallFlowLayout *)waterfallFlowLayout columnMarginInSection:(NSInteger)section
{
    CGFloat columnMargin = 0;
    if (section == 1) {
        columnMargin = 15;
    }
    
    return columnMargin;
}

/**
 *  行间距
 */
- (CGFloat)waterfallFlowLayout:(DMWaterfallFlowLayout *)waterfallFlowLayout rowMarginInSection:(NSInteger)section
{
    CGFloat rowMargin = 0;
    if (section == 0) {
        rowMargin = 10;
    } else if (section == 1) {
        rowMargin = 15;
    } else {
        rowMargin = 10;
    }
    
    return rowMargin;
}

/**
 *  UIEdgeInsets
 */
- (UIEdgeInsets)waterfallFlowLayout:(DMWaterfallFlowLayout *)waterfallFlowLayout edgeInsetsInSection:(NSInteger)section
{
    UIEdgeInsets sectionEdgeInsets = UIEdgeInsetsZero;
    if (section == 0) {
        sectionEdgeInsets = UIEdgeInsetsMake(10, 0, 10, 0);
    } else if (section == 1) {
        sectionEdgeInsets = UIEdgeInsetsMake(15, 15, 15, 15);
    } else {
       sectionEdgeInsets = UIEdgeInsetsMake(10, 0, 10, 0);
    }
    
    return sectionEdgeInsets;
}

#pragma mark - getter and setter
- (UICollectionView *)myCollectionView
{
    if (_myCollectionView == nil) {
        DMWaterfallFlowLayout *waterfallFlowLayout = [[DMWaterfallFlowLayout alloc] init];
        waterfallFlowLayout.delegate = self;
        _myCollectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 64, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height - 64) collectionViewLayout:waterfallFlowLayout];
        _myCollectionView.dataSource = self;
        _myCollectionView.backgroundColor = [UIColor whiteColor];
        _myCollectionView.delegate = self;
        [_myCollectionView registerClass:[DMSectionHeaderCollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:kDMSectionHeaderCollectionReusableViewIdentifier];
        [_myCollectionView registerClass:[DMSectionFooterCollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:kDMSectionFooterCollectionReusableViewIdentifier];
        [_myCollectionView registerClass:[DMNormalCollectionViewCell class] forCellWithReuseIdentifier:kDMNormalCollectionViewCellIdentifier];
        [_myCollectionView registerClass:[DMWaterfallCollectionViewCell class] forCellWithReuseIdentifier:kDMWaterfallCollectionViewCellIdentifier];
    }
    
    return _myCollectionView;
}

- (NSMutableArray *)dataArray
{
    if (_dataArray == nil) {
        _dataArray = [[NSMutableArray alloc] init];
    }
    
    return _dataArray;
}

效果图如下


瀑布流-1.gif

瀑布流部分是第二个section,第一个section和第三个section是正常的。

你可能感兴趣的:(iOS UICollectionView之瀑布流)