一、效果展示
二、思路分析
1> 布局的基本流程
当设置好collectionView的布局方式之后(UICollectionViewFlowLayout),当系统开始布局的时候,会调用 prepareLayout 来布局
- (void)prepareLayout;
与此同时,collectionViewCell 的每个控件的布局属性都会调用 以下方法来设置(可以重写方法来修改每个cell 的数值)
1 - (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
2> 每列 的高度计算方式
1.计算所有的cell 的高度,然后平均下来,得到itemSize 然后计算每列的高度-----> 该方法不够精确,而且极端情况下会相差太大
2.每次计算cell 的时候,找出高度最低的那一列,优先添加到该列,然后依次计算------> 该方法误差较小
Tip: 在collectionView中,contentSize 就是一个摆设,不能根据这个来计算 collectionView 的大小,系统会自动的根据 itemSize 来计算
三、核心代码实现
1 // 2 // WaterFall.h 3 // 瀑布流 4 // 5 // Created by gxiangzi on 15/9/16. 6 // Copyright © 2015年 hqu. All rights reserved. 7 // 8 9 #import <UIKit/UIKit.h> 10 11 @interface WaterFall : UICollectionViewFlowLayout 12 13 // 计算列数 14 @property (assign, nonatomic) NSInteger columCount; 15 // 所有的模型数组 16 @property (strong, nonatomic) NSArray * dataList; 17 18 @end
1 // 2 // WaterFall.m 3 // 瀑布流 4 // 5 // Created by gxiangzi on 15/9/16. 6 // Copyright © 2015年 hqu. All rights reserved. 7 // 8 9 /** 10 11 // 获得高度的办法 12 1. 计算总的高度,然后计算每个高度,最后设置itemsize 来计算 13 2. 找出最高的列,然后根据最高的列来计算 14 注意:collectionView 的contentView 是一个摆设,没有实际效果,需要根据 itemSize 来计算 15 16 */ 17 18 #import "WaterFall.h" 19 #import "Shop.h" 20 21 @interface WaterFall () 22 23 @property (nonatomic,strong) NSMutableArray * itemsAttribute; 24 25 @end 26 27 @implementation WaterFall 28 29 -(void)prepareLayout 30 { 31 [super prepareLayout]; 32 33 // self.sectionFootersPinToVisibleBounds = YES; 34 35 // 计算每列的宽度 36 CGFloat contentWidth = self.collectionView.bounds.size.width - self.sectionInset.left - self.sectionInset.right; 37 CGFloat colWidth = (contentWidth - (self.columCount - 1) * self.minimumInteritemSpacing) / self.columCount; 38 self.minimumInteritemSpacing = 10; 39 self.minimumLineSpacing = 10; 40 41 [self attribute:colWidth]; 42 } 43 44 - (void) attribute:(CGFloat) colWidth 45 { 46 NSInteger colCount[self.columCount]; 47 CGFloat colHeight[self.columCount]; 48 49 for (int i=0; i<self.columCount; ++i) 50 { 51 colHeight[i] = 0; 52 colCount[i] = 0; 53 } 54 55 56 // 定义总item高 57 CGFloat totoalItemHeight = 0; 58 59 // 定义一个可变数组,来存储 素有的属性值 60 NSMutableArray * arrayM = [NSMutableArray arrayWithCapacity:self.dataList.count]; 61 62 // 计数 63 NSInteger index = 0; 64 65 // 遍历数组,计算相关的属性 66 for (Shop * shop in self.dataList) 67 { 68 69 // 1> 建立布局属性 70 NSIndexPath * indexPath = [NSIndexPath indexPathForRow:index inSection:0]; 71 index ++; 72 UICollectionViewLayoutAttributes * attr = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; 73 74 // 2.计算当前的列数 75 // 计算是第几列 76 NSInteger col = [self shortestCol:colHeight]; 77 // 计算每一列的个数 78 colCount[col]++; 79 80 // 3.计算frame 81 CGFloat w = shop.w; 82 CGFloat h = shop.h * colWidth / w; 83 CGFloat x = self.sectionInset.left + (colWidth + self.minimumInteritemSpacing) * col; 84 CGFloat y = colHeight[col] + self.minimumLineSpacing; 85 // 累加,计算同一列下一个元素的高度 86 colHeight[col] += (h + self.minimumLineSpacing); 87 88 attr.frame = CGRectMake(x, y, colWidth, h); 89 90 // 4.计算总的高度 91 totoalItemHeight += h; 92 93 // 5.添加到 itemsAttribute 94 [arrayM addObject:attr]; 95 } 96 97 // 计算出最高的那一列 98 NSInteger highestCol = [self highestColL:colHeight]; 99 // 设置 itemSize,使用总高度的平均值 100 self.itemSize = CGSizeMake(colWidth, (colHeight[highestCol]- colCount[highestCol] * self.minimumInteritemSpacing) / colCount[highestCol]); 101 102 // 添加页脚属性 103 104 UICollectionViewLayoutAttributes * footer = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionFooter withIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]]; 105 footer.frame = CGRectMake(0, colHeight[highestCol], self.collectionView.bounds.size.width, 50); 106 107 [arrayM addObject:footer]; 108 109 self.itemsAttribute = arrayM; 110 } 111 112 113 /// 返回所有 cell 的属性数组 114 - (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect 115 { 116 return self.itemsAttribute; 117 } 118 119 /// 获得最少的那一列 120 /// 121 /// @param colHeight 列高数组 122 /// 123 /// @return 最少的列号 124 - (NSInteger) shortestCol:(CGFloat *)colHeight { 125 CGFloat min = MAXFLOAT; 126 CGFloat col = 0; 127 128 for (int i=0; i<self.columCount; ++i) 129 { 130 if (colHeight[i] < min) { 131 min = colHeight[i]; 132 col = i; 133 } 134 } 135 return col; 136 } 137 138 /// 获得最高的那一列 139 /// 140 /// @param colHeight 列高数组 141 /// 142 /// @return 最高的列号 143 - (NSInteger) highestColL:(CGFloat *)colHeight { 144 145 CGFloat max = 0; 146 CGFloat col = 0; 147 148 for (int i=0; i<self.columCount; ++i) 149 { 150 if(colHeight[i] > max) 151 { 152 max = colHeight[i]; 153 col = i; 154 } 155 } 156 157 return col; 158 } 159 160 161 #pragma mark - 懒加载 属性数组 162 - (NSMutableArray *)itemsAttribute 163 { 164 if (_itemsAttribute == nil) 165 { 166 _itemsAttribute = [NSMutableArray array]; 167 } 168 return _itemsAttribute; 169 } 170 171 @end
时间: 2024-10-10 09:13:51