美文网首页
iOS - 简单的瀑布流

iOS - 简单的瀑布流

作者: 壮骨 | 来源:发表于2017-10-12 10:54 被阅读0次

    先看看效果


    效果图

    1.创建UICollectionView

        self.collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:self.layout];
        [self.view addSubview:self.collectionView];
        self.collectionView.delegate = self;
        self.collectionView.dataSource = self;
        [self.collectionView registerClass:[PHCollectionViewCell class] forCellWithReuseIdentifier:@"PHCollectionViewCellID"];
        self.collectionView.backgroundColor = [UIColor whiteColor];
    

    2.自定义 Layout (重点)

    2.1 创建一个继承自UICollectionViewFlowLayout 的对象
    @interface PHCollectionViewFlowLayout : UICollectionViewFlowLayout
    /** 列间距 */
    @property(nonatomic,assign)CGFloat columnMargin;
    /** 行间距 */
    @property(nonatomic,assign)CGFloat rowMargin;
    /** 列数 */
    @property(nonatomic,assign)int columnsCount;
    @end
    
    2.2 重写 UICollectionViewFlowLayout 中的一些方法

    2.2.1 声明两个可变数组 一个用来存放每一列的下一个的Y值, 一个用来存放cell的Attributes

    @property (nonatomic,strong) NSMutableArray *yArray;
    @property (nonatomic,strong) NSMutableArray *attrsArray;
    
    - (NSMutableArray *)yArray{
        if (!_yArray) {
           // 不能为空 需要有每一列的初始值
            _yArray = [NSMutableArray array];
            for (int i = 0; i < self.columnsCount; i++) {
                [_yArray addObject:[NSNumber numberWithFloat:0]];
            }
        }
        return _yArray;
    }
    
    - (NSMutableArray *)attrsArray{
        if (!_attrsArray) {
            _attrsArray = [NSMutableArray array];
        }
        return _attrsArray;
    
    }
    

    2.2.2 重写: prepareLayout (每一次collocationView 刷新的数据的时候会调)

    - (void)prepareLayout{
        [super prepareLayout];
        
        // 因为是刷新所有cell  所以需要清空之前的 这里可以根据需求来定 不删除全部的 保留之前已经计算的好的Attributes
        self.yArray = nil;
        [self.attrsArray removeAllObjects];
    
        NSInteger count = [self.collectionView numberOfItemsInSection:0];
       
    
        for (NSInteger i = 0; i < count; i++) {
            NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
            [self.attrsArray addObject:[self layoutAttributesForItemAtIndexPath:indexPath]];
        }
    
    
    }
    - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
    {
        UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
        CGFloat w = (self.collectionView.bounds.size.width - self.sectionInset.left - self.sectionInset.right - self.columnMargin * (self.columnsCount - 1)) / self.columnsCount;
        CGFloat h = 100 + arc4random_uniform(100); // 重点 这里的高度设开发情况定 这里是只是举个例子 随机高度
        
        // 找到Y值最小的那一列
        CGFloat minY = [self.yArray[0] floatValue];
        int minYIndex = 0;
        for (int j = 1; j < self.yArray.count; j++) {
            CGFloat y = [self.yArray[j] floatValue];
            if (y < minY) {
                minY = y;
                minYIndex = j;
            }
        }
        
        CGFloat y = minY;
         // 将该列下一个的Y值计算出来 并存放起来
        self.yArray[minYIndex] = [NSNumber numberWithFloat:y + h + self.rowMargin];
        
        CGFloat x = self.sectionInset.left + (self.columnMargin + w) * yIndex;
        // 上述只是解释原理, frame值的生成由各自需求而定
        attributes.frame = CGRectMake(x, y, w, h);
    
        return attributes;
    }
    // 系统的方法 返回每一个cell的 Attributes 在 prepareLayout 之后调用
    - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{
        return self.attrsArray;
    }
    

    2.2.2 重写 collectionViewContentSize 方法 返回UICollocationView的ContentSize

    - (CGSize)collectionViewContentSize{
        // 根据需求来返回 这里实现的是纵向滚动的效果 所以将最大的y值 返回即可
        return CGSizeMake(self.collectionView.frame.size.width, [self contentSizeHeight]);
    }
    - (CGFloat)contentSizeHeight{
        CGFloat maxh = [self.yArray[0] floatValue];
        for (int i = 1; i < self.yArray.count; i++) {
            CGFloat h = [self.yArray[i] floatValue];
            if (h > maxh) {
                maxh = h;
            }
        }
        return maxh;
    }
    
    实现以上几步 就可以做出简单的瀑布流效果
    有个小问题
    测试代码
    -(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
        PHCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"PHCollectionViewCellID" forIndexPath:indexPath];
        
        if (indexPath.row == 10) {
            NSLog(@" %@",NSStringFromCGRect(cell.contentView.frame));// 变
            NSLog(@" %@",NSStringFromCGRect(cell.frame));  // 不变
            NSLog(@"------------");
        }
        
        cell.label.text = [NSString stringWithFormat:@"%ld - %ld",indexPath.section,indexPath.item];
        cell.backgroundColor = [self randomColor];
        
        return cell;
    }
    
    打印结果

    测试中发现 cell的frame一直没有变 但是 cell.contentView 变了

    发现在上述代码中 添加 [cell layoutSubviews]; 重置cell的子控件布局 就OK 了

    打印结果2

    不管有没有重新走 prepareLayout 他都会变
    其中的 Attributes 计算也没有错 已经打印 并且cell的frame 打印也是正确的
    就只有cell的contentView的frame变了
    不太明白原因,希望有哪位哥们帮忙解答下,感谢

    相关文章

      网友评论

          本文标题:iOS - 简单的瀑布流

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