1. 建立「WYWaterflowLayout」繼承製 「UICollectionViewLayout」。數組
2. 在「ViewController」 中導入「WYWaterflowLayout」類。並建立,建立的代碼以下dom
@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>atom
- (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」的方法,這四個類是必需要寫的。spa
// 初始化 - (void)prepareLayout; // 決定cell的排布 - (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect; // 返回indexPath位置cell對應的佈局屬性 - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath; - (CGSize)collectionViewContentSize
總體代碼以下:code
// // 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