瀑布流布局

作者: Mr丶炎 | 来源:发表于2016-07-14 20:17 被阅读36次
    瀑布流.png

    瀑布流布局是现在很常用的布局方式,用collectionView实现。要设计它关键就是知道cell的位置,具体在那一列上,而且是最短的那列,然后在其下面增加。

    它的宽度,用collectionView减两边的间隙和中间的间隙,然后除以列数
    高度 一般由外界确定
    x值 先找到最短的那一列,左间距加上当前列数乘以宽度加间隙
    y值 最短列的高度加行间距

    布局我们是基于UICollectionViewLayout类
    要注意这四个方法

    /** 初始化 */
    - (void)prepareLayout {
    }
    
    /** 决定cell的排布, 这个方法会频繁调用  */
    - (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
        return self.attrsArray;
    }
    
    /** 返回indexPath位置cell对应的布局 */
    - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
    }
    
     /** 滚动范围 */
    - (CGSize)collectionViewContentSize {
    }
    

    先定义些有用的变量

    /** 默认的列数 */
    static const NSInteger LXYDefaultColumnCount = 3;
    
    /** 每一列之间的间距 */
    static const CGFloat LXYDefaultColumnMargin = 10;
    
    /** 每一行之间的间距 */
    static const CGFloat LXYDefaultRowMargin = 10;
    
    /** 边缘间距, 这是一个知识点,之间赋值给UIEdgeInsets的值 */
    static const UIEdgeInsets LXYDefaultEdgeInsets = {10, 10, 10, 10};
    
    @interface LXYWaterFlowLayout ()
    
    /** 存放所有cell的布局属性 */
    @property (nonatomic, strong) NSMutableArray *attrsArray;
    
    /** 存放所有列的当前高度 */
    @property (nonatomic, strong) NSMutableArray *columnHeights;
    

    其他代码

    /** 初始化 */
    - (void)prepareLayout {
        [super prepareLayout];
        
        // 先清除之前计算的所有高度
        [self.columnHeights removeAllObjects];
        for (NSInteger i = 0; i < LXYDefaultColumnCount; i++) {
            // 默认为顶部高度
            [self.columnHeights addObject:@(LXYDefaultEdgeInsets.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位置对应的布局属性
            UICollectionViewLayoutAttributes *attrs = [self layoutAttributesForItemAtIndexPath:indexPath];
            
            [self.attrsArray addObject:attrs];
            
        }
            
    }
    
    /** 决定cell的排布, 这个方法会频繁调用  */
    - (NSArray<UICollectionViewLayoutAttributes *> *)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 - LXYDefaultEdgeInsets.left - LXYDefaultEdgeInsets.right - (LXYDefaultColumnCount - 1) * LXYDefaultColumnMargin) / LXYDefaultColumnCount;
        
        CGFloat h = 130 + arc4random_uniform(150);
        
        // 找出高度最短的那一列
        NSInteger destColumn = 0;
        CGFloat minColumnHeight = [self.columnHeights[0] doubleValue];
        for (NSInteger i = 1; i < LXYDefaultColumnCount; i++) {
            // 获取第i列的高度
            CGFloat columnHeight = [self.columnHeights[i] doubleValue];
            if (minColumnHeight > columnHeight) {
                minColumnHeight = columnHeight;
                destColumn = i;
            }
        }
        
        CGFloat x = LXYDefaultEdgeInsets.left + destColumn * (w + LXYDefaultColumnMargin);
        
        CGFloat y = minColumnHeight + LXYDefaultRowMargin;
        
        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 < LXYDefaultColumnCount; i++) {
            // 获取第i列的高度
            CGFloat columnHeight = [self.columnHeights[i] doubleValue];
            if (maxColumnHeight < columnHeight) {
                maxColumnHeight = columnHeight;
            }
        }
    

    使用瀑布流

    // 创建布局
        LXYWaterFlowLayout *layout = [[LXYWaterFlowLayout alloc] init];
        
        // 创建collectionView
        CGFloat collectionW = self.view.frame.size.width;
        UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:layout];
        
        collectionView.dataSource = self;
        collectionView.backgroundColor = [UIColor whiteColor];
        [self.view addSubview:collectionView];
        
        // 注册
        [collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:LXYShopId];
    
    

    实现数据源方法

    #pragma mark - UICollectionViewDataSource
    
    - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
        
        return 50;
    }
    
    - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
        
        UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:LXYShopId forIndexPath:indexPath];
        
        cell.backgroundColor = [UIColor orangeColor];
        
        NSInteger tag = 10;
        UILabel *label = (UILabel *)[cell.contentView viewWithTag:tag];
        if (label == nil) {
            label = [[UILabel alloc] init];
            label.tag = tag;
            [cell.contentView addSubview:label];
        }
        
        label.text = [NSString stringWithFormat:@"%zd", indexPath.item];
        [label sizeToFit];
        
        return cell;
    }
    

    效果请看https://github.com/liangxingyan/layout-.git

    相关文章

      网友评论

        本文标题:瀑布流布局

        本文链接:https://www.haomeiwen.com/subject/cjzejttx.html