在實現瀑布流以前先來看看瀑布流的雛形(此方法的雛形 UICollectionView)數組
對於UICollectionView咱們有幾點注意事項dom
圖(一)ide
如圖,模擬器上展現的是不少方格,可是值得注意的是他們是有規則的。佈局
雖然看上去很整潔可是並不美觀。atom
咱們所說的要實現瀑布流就是要實現它的不整潔,可是規律(這裏我說的是規律)設計
前面說了UIcollectionView的大部分操做在FlowLayout上,固然也包括格局部署。orm
爲了實現瀑布流咱們所要實現的即是改變他的格局部署。對象
下面是實現的代碼部分(不提供demo了 很簡單)blog
我在註釋中簡單介紹。圖片
---
// // ViewController.m // CX-瀑布流UIcollectionView實現 // // Created by ma c on 16/4/8. // Copyright © 2016年 bjsxt. All rights reserved. // #import "ViewController.h" #import "CXCollectionViewCell.h" #import "CXCollectionViewLayout.h" static NSString * identifier = @"cellID"; @interface ViewController ()<UICollectionViewDataSource> //所要展現的UICollectionView @property (nonatomic, strong) UICollectionView * collectionView; @end @implementation ViewController #pragma mark - <懶加載> - (UICollectionView *)collectionView { if (!_collectionView) { //初始化咱們自定義的flowLayout CXCollectionViewLayout * flowLayout = [[CXCollectionViewLayout alloc]init]; //初始化collectionView _collectionView = [[UICollectionView alloc]initWithFrame:self.view.bounds collectionViewLayout:flowLayout]; //設置數據源(collectionView的命根子) _collectionView.dataSource = self; //註冊咱們自定義的cell [_collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([CXCollectionViewCell class]) bundle:nil] forCellWithReuseIdentifier:identifier]; } return _collectionView; } #pragma mark - <life> - (void)viewDidLoad { [super viewDidLoad]; //在self.view上添加--- [self.view addSubview:self.collectionView]; } #pragma mark - <UICollectionViewDataSource> //這裏返回的是item的個數 返回100 - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{ return 100; } //這裏返回的是cell 咱們能夠在這裏進行一些簡單的操做 -(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ CXCollectionViewCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath]; //爲了瀑布流的實現細節咱們添加的Label cell.label.text = [NSString stringWithFormat:@"%zd",indexPath.item]; //cell的背景色 cell.backgroundColor = [UIColor orangeColor]; return cell; } @end
---
// // CXCollectionViewLayout.m // CX-瀑布流UIcollectionView實現 // // Created by ma c on 16/4/8. // Copyright © 2016年 bjsxt. All rights reserved. // #import "CXCollectionViewLayout.h" //瀑布流的列數 static NSInteger CXcolumnCount = 3; //瀑布流的內邊距 static UIEdgeInsets CXdefaultEdgeInsets = {20,15,10,15}; //cell的列間距 static NSInteger CXcolumnMagin = 10; //cell的行間距 static NSInteger CXrowMagin = 10; @interface CXCollectionViewLayout () //存放全部cell 的佈局屬性 @property (nonatomic, strong) NSMutableArray * CXattrsArray; //縮放全部列的高度 @property (nonatomic, strong) NSMutableArray * CXcolumnHeights; @end @implementation CXCollectionViewLayout #pragma mark - <懶加載> - (NSMutableArray *)CXattrsArray{ if (!_CXattrsArray) { _CXattrsArray = [NSMutableArray array]; } return _CXattrsArray; } - (NSMutableArray *)CXcolumnHeights{ if (!_CXcolumnHeights) { _CXcolumnHeights = [NSMutableArray array]; } return _CXcolumnHeights; } #pragma mark - <準備佈局> //準備佈局(佈局前自動執行) - (void) prepareLayout{ //重寫此方法必定要記得super [super prepareLayout]; //在實際操做中咱們的數據並不會固定不變的,所以咱們每次佈局前最好要清空以前存儲的屬性 //清空存放全部列的高度 //清空存放全部cell的不去屬性 [self.CXcolumnHeights removeAllObjects]; [self.CXattrsArray removeAllObjects]; //首先爲第一行的cell附高度 for (NSInteger i = 0; i < CXcolumnCount; i ++) { //數組裏只能存放對象 [self.CXcolumnHeights addObject:@(CXdefaultEdgeInsets.top)]; } //下面開始建立每個cell的佈局屬性 而且添加到存儲cell佈局屬性的數組中 //cell總個數 由於這裏只要一個section NSInteger count = [self.collectionView numberOfItemsInSection:0]; for (NSInteger i = 0; i < count; i ++) { // 建立位置 即indexPath NSIndexPath * indexPath = [NSIndexPath indexPathForItem:i inSection:0]; //獲取indexPath對應的cell佈局屬性 UICollectionViewLayoutAttributes * attributes = [self layoutAttributesForItemAtIndexPath:indexPath]; //把獲取到的佈局屬性添加到數組中 [self.CXattrsArray addObject:attributes]; } //準備佈局的工做到這裏就結束了 } //返回全部cell佈局屬性 及總體cell 的排布 - (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{ return self.CXattrsArray; } //返回cell 的佈局屬性 - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{ //建立佈局屬性 UICollectionViewLayoutAttributes * CXattributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; //獲取collectionView 的寬 CGFloat collectionViewWidth = self.collectionView.frame.size.width; //下面的一部分是獲取cell的frame(佈局屬性) CGFloat width; CGFloat height; CGFloat X; CGFloat Y; //獲取width width = (collectionViewWidth - CXdefaultEdgeInsets.left - CXdefaultEdgeInsets.right - (CXcolumnCount - 1) * CXcolumnMagin) / CXcolumnCount; //獲取height //在實際開發中heigh並非真正的隨機 而是根據數據來決定height 在這裏展現初步的介紹其原理 所以採用大於100小於150的隨機數 height = 100 + arc4random_uniform(50); //獲取X (瀑布流的實現重點就在cell的X,Y值獲取) //設置一個列數的中間變量 NSInteger tempColumn = 0; //設置高度小的中間變量 在這裏咱們把第0列的高度給他,這樣能夠減小循環次數,提升效率 CGFloat minColumnHeight = [self.CXcolumnHeights[0] doubleValue]; for (NSInteger i = 1; i < CXcolumnCount; i ++) { if (minColumnHeight > [self.CXcolumnHeights[i] doubleValue]) { minColumnHeight = [self.CXcolumnHeights[i] doubleValue]; tempColumn = i; } } X = CXdefaultEdgeInsets.left + (width + CXcolumnMagin) * tempColumn; //獲取Y Y = minColumnHeight; if (Y != CXdefaultEdgeInsets.top) { Y += CXrowMagin; } //設置cell的frame CXattributes.frame = CGRectMake(X, Y, width, height); //更新高度最矮的那列的高度 self.CXcolumnHeights[tempColumn] = @(CGRectGetMaxY(CXattributes.frame)); return CXattributes; } //返回collegeView的Content的大小 - (CGSize)collectionViewContentSize{ //雖然說返回的是大小,可是咱們這裏主要的是height CGFloat maxColumnHeight = [self.CXcolumnHeights[0] doubleValue]; for (NSInteger i = 1; i < CXcolumnCount; i++) { CGFloat columnHeight = [self.CXcolumnHeights[i] doubleValue]; if (maxColumnHeight < columnHeight) { maxColumnHeight = columnHeight; } } return CGSizeMake(0, maxColumnHeight + CXdefaultEdgeInsets.bottom); } @end
到此爲止瀑布流的實現也就結束了。
在這裏說明幾點值得注意的地方。