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