iOS之瀑布流布局设计

Posted 学东哥哥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS之瀑布流布局设计相关的知识,希望对你有一定的参考价值。

#import "CXDWaterflowLayout.h"

/** 默认的列数 */
static const NSInteger CXDDefaultColumnCount = 3;
/** 每一列之间的间距 */
static const CGFloat CXDDefaultColumnMargin = 10;
/** 每一行之间的间距 */
static const CGFloat CXDDefaultRowMargin = 10;
/** 边缘间距 */
static const UIEdgeInsets CXDDefaultEdgeInsets = {10, 10, 10, 10};

@interface CXDWaterflowLayout()
/** 存放所有cell的布局属性 */
@property (nonatomic, strong) NSMutableArray *attrsArray;
/** 存放所有列的当前高度 */
@property (nonatomic, strong) NSMutableArray *columnHeights;
@end

@implementation CXDWaterflowLayout

- (NSMutableArray *)columnHeights
{
    if (!_columnHeights) {
        _columnHeights = [NSMutableArray array];
    }
    return _columnHeights;
}

- (NSMutableArray *)attrsArray
{
    if (!_attrsArray) {
        _attrsArray = [NSMutableArray array];
    }
    return _attrsArray;
}

/**
 * 初始化
 */
- (void)prepareLayout
{
    [super prepareLayout];
    
    // 清除以前计算的所有高度
    [self.columnHeights removeAllObjects];
    for (NSInteger i = 0; i < CXDDefaultColumnCount; i++) {
        [self.columnHeights addObject:@(CXDDefaultEdgeInsets.top)];
    }

    // 清除之前所有的布局属性
    [self.attrsArray 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.attrsArray addObject:attrs];
    }
}

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

/**
 * 返回indexPath位置cell对应的布局属性
 */
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
    // 创建布局属性
    UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    
    // collectionView的宽度
    CGFloat collectionViewW = self.collectionView.frame.size.width;
    
    // 设置布局属性的frame
    CGFloat w = (collectionViewW - CXDDefaultEdgeInsets.left - CXDDefaultEdgeInsets.right - (CXDDefaultColumnCount - 1) * CXDDefaultColumnMargin) / CXDDefaultColumnCount;
    CGFloat h = 50 + arc4random_uniform(100);
    
    // 找出高度最短的那一列
    NSInteger destColumn = 0;
    CGFloat minColumnHeight = [self.columnHeights[0] doubleValue];
    for (NSInteger i = 1; i < CXDDefaultColumnCount; i++) {
        // 取得第i列的高度
        CGFloat columnHeight = [self.columnHeights[i] doubleValue];
        
        if (minColumnHeight > columnHeight) {
            minColumnHeight = columnHeight;
            destColumn = i;
        }
    }
    
    CGFloat x = CXDDefaultEdgeInsets.left + destColumn * (w + CXDDefaultColumnMargin);
    CGFloat y = minColumnHeight;
    if (y != CXDDefaultEdgeInsets.top) {
        y += CXDDefaultRowMargin;
    }
    attrs.frame = CGRectMake(x, y, w, h);
    
    // 更新最短那列的高度
    self.columnHeights[destColumn] = @(CGRectGetMaxY(attrs.frame));
    
    return attrs;
}

- (CGSize)collectionViewContentSize
{
    CGFloat maxColumnHeight = [self.columnHeights[0] doubleValue];
    for (NSInteger i = 1; i < CXDDefaultColumnCount; i++) {
        // 取得第i列的高度
        CGFloat columnHeight = [self.columnHeights[i] doubleValue];
        
        if (maxColumnHeight < columnHeight) {
            maxColumnHeight = columnHeight;
        }
    }
    return CGSizeMake(0, maxColumnHeight + CXDDefaultEdgeInsets.bottom);
}

@end

ps:继承UICollectionViewLayout类,实现其中方法,找到高度最短的那一列填充对应数据即可

以上是关于iOS之瀑布流布局设计的主要内容,如果未能解决你的问题,请参考以下文章

关于waterfall 瀑布流布局出现布局错乱的问题

vue+uniapp瀑布流布局多种实现方式

原生JS实现瀑布流布局

瀑布流布局

网页瀑布流布局jQuery实现代码

iOS开发进阶 - 自定义UICollectionViewLayout实现瀑布流布局