标签:
一、效果展示
二、思路分析
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
标签:
原文地址:http://www.cnblogs.com/gaox97329498/p/4818104.html