zoukankan      html  css  js  c++  java
  • WaterfallFlowLayout瀑布流用重写UICollectionViewFlowLayout类实现

    最近调研瀑布流,在gitHub上下了个Demo发现它的所有视图都是用Main.storyboard拖的, 自己研究半天没研究明白;

    然后就又找了一个Demo, 它的视图全是手打的, 但是实现的方法不太好,就将这俩Demo结合了一下:

    用了gitHub的实现原理 和 另一个Demo的视图.


    实现瀑布流最重要的一步就是重写UICollectionViewFlowLayout类, 下面就简单介绍一下实现原理

    本方法实现的仅是高度不一样, 宽度是根据屏宽平均分的;

    当创建UICollectionView的UICollectionViewFlowLayout属性时,给它传进去了两个属性: 列数, 和需要显示的Model数组 (这里是商品model(图片,价钱))

    WaterfallFlowLayout.h

    //  WaterfallFlowLayout.h
    @interface WaterfallFlowLayout : UICollectionViewFlowLayout
    
    // 总列数
    @property (nonatomic, assign) NSInteger columnCount;
    
    // 商品数据数组
    @property (nonatomic, strong) NSArray *goodsArray;
    
    @end


    在.m文件里就根据这两个属性计算每个frame的大小, 用一个数组记录每列的高度, 每次计算frame时就将它放到最短列下面:

    仅为计算item属性数组  和 itemSize, 然后在layoutAttributesForElementsInRect返回了该数组,就算是改变了每个item的frame了

    <span style="font-family: Arial, Helvetica, sans-serif;">//  WaterfallFlowLayout.m</span>
    #import "WaterfallFlowLayout.h"
    #import "Good.h"
    
    @interface WaterfallFlowLayout ()
    // 所有item的属性的数组
    @property (nonatomic, strong) NSArray *layoutAttributesArray;
    @end
    
    @implementation WaterfallFlowLayout
    
    /**
     *  布局准备方法 当collectionView的布局发生变化时 会被调用
     *  通常是做布局的准备工作 itemSize.....
     *  UICollectionView 的 contentSize 是根据 itemSize 动态计算出来的
     */
    - (void)prepareLayout {
        // 根据列数 计算item的宽度 宽度是一样的
        CGFloat contentWidth = self.collectionView.bounds.size.width - self.sectionInset.left - self.sectionInset.right; //减去分区的边框
        CGFloat marginX = self.minimumInteritemSpacing;  //最小左右间距
        CGFloat itemWidth = (contentWidth - marginX * (self.columnCount - 1)) / self.columnCount;
        
        // 计算布局属性
        [self computeAttributesWithItemWidth:itemWidth];
    }
    
    #pragma mark 根据itemWidth计算布局属性
    - (void)computeAttributesWithItemWidth:(CGFloat)itemWidth {
        
        // 定义一个列高数组 记录每一列的总高度
        CGFloat columnHeight[self.columnCount];
        // 初始化
        for (int i = 0; i < self.columnCount; i++) {
            columnHeight[i] = self.sectionInset.top;
        }
        
        // 遍历 goodsList 数组计算相关的属性
        NSMutableArray *attributesArray = [NSMutableArray arrayWithCapacity:self.goodsArray.count];
        
        //因为item数是跟当前的商品数一样的 每次改变都动态计算一遍
        for (NSInteger i = 0; i < self.goodsArray.count; i++) {
            Good *good = self.goodsArray[i];
            // 建立布局属性
            NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
            // 获得当前item的布局属性
            UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
            // 找出最短列号
            NSInteger column = [self shortestColumn:columnHeight];
            // X值
            CGFloat itemX = (itemWidth + self.minimumInteritemSpacing) * column + self.sectionInset.left;
            // Y值 = 当前列的总高度
            CGFloat itemY = columnHeight[column];
            // 等比例缩放 计算item的高度
            CGFloat itemH = good.h * itemWidth / good.w;
            // 设置frame
            attributes.frame = CGRectMake(itemX, itemY, itemWidth, itemH);
            [attributesArray addObject:attributes];
            
            //!!!!!!!!
            self.itemSize = CGSizeMake(itemWidth, itemH);
    
            // 累加当前列高
            columnHeight[column] += itemH + self.minimumLineSpacing;
            
        }
        // 给属性数组设置数值
        self.layoutAttributesArray = attributesArray.copy;
    }
    
    #pragma mark 找出columnHeight数组中最短列号 追加数据的时候追加在最短列中
    - (NSInteger)shortestColumn:(CGFloat *)columnHeight {
        
        CGFloat min = CGFLOAT_MAX;
        NSInteger column = 0;
        // 循环列高数组
        for (int i = 0; i < self.columnCount; i++) {
            if (columnHeight[i] < min) {
                min = columnHeight[i];
                column = i;
            }
        }
        return column;
    }
    
    /**
     *  跟踪效果:当到达要显示的区域时 会计算所有显示item的属性
     *           一旦计算完成 所有的属性会被缓存 不会再次计算
     *  @return 返回布局属性(UICollectionViewLayoutAttributes)数组
     */
    - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
        // 直接返回计算好的布局属性数组
        return self.layoutAttributesArray;
    }


    一下是Demo下载地址:

    http://download.csdn.net/detail/margaret_mo/9417425





  • 相关阅读:
    Hibernate学习笔记
    Servlet:从入门到实战学习(3)---Servlet实例【图文】
    Servlet:从入门到实战学习(2)---Servlet生命周期
    Servlet:从入门到实战学习(1)---全·环境配置
    java复习(9)---数据库JDBC
    java复习(8)---I/O
    java复习(7)---集合类、泛型
    java复习(6)---异常处理
    C#尝试读取或写入受保护的内存。这通常指示其他内存已损坏
    C# TTS 文本转语音中断实现方式
  • 原文地址:https://www.cnblogs.com/moxiaoyan33/p/5309253.html
Copyright © 2011-2022 走看看