1. 创建“WYWaterflowLayout”继承制 “UICollectionViewLayout”。
2. 在“ViewController” 中导入“WYWaterflowLayout”类。并创建,创建的代码如下
@property (nonatomic,weak) UICollectionView *collectionView;
- (void)CircleLayout { WYWaterflowLayout *layout = [[WYWaterflowLayout alloc] init]; // 创建CollectionView UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:layout]; collectionView.dataSource = self; collectionView.backgroundColor = [UIColor whiteColor]; [self.view addSubview:collectionView]; self.collectionView = collectionView; // 使用系统自带的类注册 // [collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:WYShopID]; // 使用自定义类注册 [collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([XMGShopCell class]) bundle:nil] forCellWithReuseIdentifier:WYShopID]; }
3. 数据源<UICollectionViewDataSource>
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { self.collectionView.footer.hidden = self.shops.count == 0; return self.shops.count; } - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { XMGShopCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:WYShopID forIndexPath:indexPath]; XMGShop *shopses = self.shops[indexPath.item]; cell.shop = shopses; return cell; }
4. 写 “WYWaterflowLayout”的方法,这四个类是必须要写的。
// 初始化 - (void)prepareLayout; // 决定cell的排布 - (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect; // 返回indexPath位置cell对应的布局属性 - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath; - (CGSize)collectionViewContentSize
整体代码如下:
// // WYWaterflowLayout.m // 瀑布流 // // Created by baojia on 16/8/26. // Copyright © 2016年 OS. All rights reserved. // #import "WYWaterflowLayout.h" /** 默认的列数 */ static const NSInteger WYColumnCount = 3 ; /** 每列之间的间距 */ static const CGFloat WYColumnMargin = 10 ; /** 每行之间的间距 */ static const CGFloat WYRowMarage = 20; /** 边缘距离 */ static const UIEdgeInsets WYEdgeInsets = {10,10,10,10}; @interface WYWaterflowLayout () @property (nonatomic,strong) NSMutableArray *attrsArray; /** 存放所有列的当前高度 */ @property (nonatomic,strong) NSMutableArray *columnHeights; @end @implementation WYWaterflowLayout - (NSMutableArray *)columnHeights { if (_columnHeights == nil) { _columnHeights = [NSMutableArray array]; } return _columnHeights ; } - (NSMutableArray *)attrsArray { if (_attrsArray == nil) { _attrsArray = [NSMutableArray array]; } return _attrsArray ; } // 初始化 - (void)prepareLayout { [super prepareLayout]; // 清楚以前计算的所有高度 [self.columnHeights removeAllObjects]; for (NSInteger i = 0; i < WYColumnCount; i++) { [self.columnHeights addObject:@(WYEdgeInsets.top)]; } // 清空之前所有的布局属性 [self.attrsArray removeAllObjects]; // 添加布局属性 [self arrayPrepareLayout]; } // 决定cell的排布 - (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect { // 这个方法会频繁的调用,每次这个界面进行滚动的时候都会调用这个方法,当这个类继承制“UICollectionViewLayout”的时候。 // 瀑布流算好一遍就可以了,所以可以放在初始化中弄。 return self.attrsArray; } // 返回indexPath位置cell对应的布局属性 - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath { // 2. 创建布局属性 UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; // collectionView的宽度 CGFloat collectionView_W = self.collectionView.frame.size.width; // 3. 设置布局属性的frame CGFloat attrs_W = (collectionView_W - WYEdgeInsets.left - WYEdgeInsets.right - (WYColumnCount - 1) * WYColumnMargin) / WYColumnCount; CGFloat attrs_H = 50 + arc4random_uniform(100); /* 第一种方法 // 3.1 找出高度最短的那一列 __block NSInteger destColumn = 0 ; __block CGFloat minColumnHeight = MAXFLOAT; [self.columnHeights enumerateObjectsUsingBlock:^(NSNumber *columnHeightNumber, NSUInteger idx, BOOL * _Nonnull stop) { CGFloat columnHeight = columnHeightNumber.doubleValue; if (minColumnHeight > columnHeight) { minColumnHeight = columnHeight; destColumn = idx; } }]; */ // 第二种写法 NSInteger destColumn = 0; CGFloat mincolumnHeight = [self.columnHeights[0] doubleValue]; for (NSInteger i = 1; i < WYColumnCount; i++) { // 取得第一列的高度 CGFloat columnHeight = [self.columnHeights[i] doubleValue]; if (mincolumnHeight > columnHeight) { mincolumnHeight = columnHeight; destColumn = i; } } CGFloat attrs_X = WYEdgeInsets.left + destColumn * (attrs_W + WYColumnMargin); CGFloat attrs_Y = mincolumnHeight; if (attrs_Y != WYEdgeInsets.top) { attrs_Y += WYRowMarage; } attrs.frame = CGRectMake(attrs_X, attrs_Y, attrs_W, attrs_H); // 4. 更新最短那列的高度 self.columnHeights[destColumn] = @(CGRectGetMaxY(attrs.frame)); return attrs; } - (CGSize)collectionViewContentSize { CGFloat maxColumnHeight = [self.columnHeights[0] doubleValue]; for (NSInteger i = 1; i < WYColumnCount ; i++) { // 取得第i列额高度 CGFloat columnHeight = [self.columnHeights[i] doubleValue]; if (maxColumnHeight < columnHeight) { maxColumnHeight = columnHeight; } } return CGSizeMake(0, maxColumnHeight + WYEdgeInsets.bottom); } #pragma mark - cell的排布 - (NSMutableArray *)arrayPrepareLayout { // 1. 创建一个数组(存放所有cell的布局属性) // NSMutableArray *arrayM = [NSMutableArray array]; // 2. 开始创建每一个cell对应的布局属性 NSInteger count = [self.collectionView numberOfItemsInSection:0]; for (NSInteger i = 0 ; i < count; i++) { // 1. 创建位置 NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0]; // 2. 获取indexPath位置cell对应的布局 UICollectionViewLayoutAttributes *attrs = [self layoutAttributesForItemAtIndexPath:indexPath]; [self.attrsArray addObject:attrs]; } return self.attrsArray; } @end