最近调研瀑布流,在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
仅为计算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