起首是後果演示
特色:可以自在設置瀑布流的總列數(後果演示為2列)
固然iphone手機的體系相冊沒有應用這類結構後果,瀑布流仍然是一種很罕見的結構方法!!!上面來具體引見若何完成這類結構.
起首應用的類是UICollectionView
我們要做的是自界說UICollectionViewCell和UICollectionViewLayout
1、自界說UICollectionViewCell類,只須要一個UIImageView便可,frame占滿全部cell.
2、重點是自界說UICollectionViewLayout,留意必定要繼續於UICollectionViewLayout,萬萬別繼續於UIColletionViewFlowLayout.
3、別的還須要盤算圖片高度.
為何要自界說UICollectionViewLayout ?
由於我們須要設置每一個item的高度和地位, 留意這裡是地位, 我們真的會設置每一個item的地位的信任我!!!自界說UICollectionViewLayout必需要重寫三個協定辦法,前面會講到.
為何要盤算圖片高度 ?
由於圖片寬度固定,所以須要依照圖片的比例來盤算高度,使圖片等比例顯示.如許的利益是,媽媽不再用擔憂我的照片被拉伸的奇形怪狀了...並且還須要用圖片的高度來盤算全部CollectionView的contentSize...打完出工!!!
主菜來了!!!
以下內容均在自界說的CustomCollectionViewLayout類裡邊
//自界說UICollectionViewLayout必需要重寫的三個協定辦法 //1.盤算每一個item的年夜小和地位 - (void)prepareLayout; //2.前往每一個item的結構屬性 - (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect; //3.前往collectionView的總高度 - (CGSize)collectionViewContentSize;
可以看到第三個辦法應用了Nullability和泛型,體系的辦法都添加了IOS 9新特征。
經由過程上邊的三個辦法名我們可以年夜致懂得須要去做甚麼.說一下第二個辦法,須要前往一個數組,數組寄存結構屬性(UICollectionViewLayoutAttributes)對象.那末我們須要寫一個屬性數組(attributesArray),將結構屬性放入這個屬性數組並前往.
還須要甚麼呢 ?看了文章開首的同伙應當留意到了,設置瀑布流的列數固然得有個屬性(numberOfColumns)來表現列數.
請留意,由於要在內部設置列數,所以這個屬性須要寫在自界說類的.h文件中
別的為了便利,界說一個屬性(itemWidth)來表現item的寬度
再界說一個屬性(contentHeight)來表現全部collectionView的contenView的高度
起首是初始化,並沒有甚麼成績
- (instancetype)init { self = [super init]; if (self) { _attributesArray = [NSMutableArray array]; // 默許值設置為2列 _numberOfColumns = 2; _contentHeight = 0.0f; _cellMargin = 5.0f;/**< 用來表現間距的屬性 */ } return self; }
然後是getter辦法,只須要應用點語法便可獲得itemWidth的值(由於它就是固定的)
- (CGFloat)itemWidth { //一切邊距的和.兩列時有三個邊距, 三列時有四個邊距,邏輯壯大就是好... CGFloat allMargin = (_numberOfColumns + 1) * _cellMargin; //除去界限以後的總寬度 CGFloat noMarginWidth = CGRectGetWidth(self.collectionView.bounds) - allMargin; //出去邊距的總寬度除以列數獲得每列的寬度(也就是itemWidth) return noMarginWidth / _numberOfColumns; }
---接上去是難點---
必需重寫的第一個辦法
- (void)prepareLayout { // 界說變量記載高度最小的列,初始為第0列高度最小. #pragma mark - 留意這個是從0開端算的啊!!! NSInteger shortestColumn = 0; #pragma mark - 留意這個是從0開端算的啊!!! // 存儲每列的總高度.由於添加圖片的列高度會變,所以須要界說一個數組來記載列的總高度. NSMutableArray *columnHeightarray = [NSMutableArray array]; // 設置列的初始高度為邊距的高度,沒缺點!!! for (int i = 0; i < _numberOfColumns; i++) { // 一切列初始高度均設置為cell的間距 [columnHeightarray addObject:@(_cellMargin)]; } // 遍歷collectionView中第 0 區中的一切item for (int i = 0; i < [self.collectionView numberOfItemsInSection:0]; i++) { //須要用到這個玩意,提早拿到. NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0]; // 創立體系須要的結構屬性對象,看後邊的參數就曉得這就是每一個item的結構屬性了 UICollectionViewLayoutAttributes *layoutAttributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath: indexPath]; // 將結構屬性放入數組中,這個數組固然是一開端界說的結構屬性數組了 [_attributesArray addObject:layoutAttributes]; // 設置每一個item的地位(x, y, width, height) // 橫坐標的肇端地位 #pragma mark - 好比一共兩列,如今要放一張圖片上去,須要放到高度最小的那一列. #pragma mark - 假定第0列最短,那末item的x坐標就是從一個邊距寬度那邊開端. #pragma mark - (itemWidth + cellMargin)為一個全體 CGFloat x = (self.itemWidth + _cellMargin) * shortestColumn + _cellMargin; // 縱坐標就是 總高度數組 中最小列對應的高度 #pragma mark - 圖片一直是添加在高度最小的那一列 CGFloat y = [columnHeightarray[column] floatValue];/**<留意類型轉換 */ // 寬度沒甚麼好說的 CGFloat width = self.itemWidth; #pragma mark - 這裡給自界說的類聲清楚明了一個協定,經由過程協定獲得圖片的高度,挪用機會就是須要item高度的時刻 #pragma mark - 將Item的寬度傳給署理人(ViewController),VC盤算好高度後將高度前往給自界說類 #pragma mark - 也就是↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ CGFloat height = [self.delegate collectionView:self.collectionView layout:self width:self.itemWidth heightForItemAtIndexPath:indexPath]; // 年夜功樂成,設置item的地位信息,沒甚麼好說 layoutAttributes.frame = CGRectMake(x, y, width, height); // 上邊廢了半天勁放了一個item上去了,總高度數組是否是該更新一下數據了 columnHeightArray[shortestColumn] = @([columnHeightArray[shortestColumn] floatValue] + height + _cellMargin); // 全部內容的高度,經由過程比擬獲得較年夜值作為全部內容的高度 self.contentHeight = MAX(self.contentHeight, [columnHeightArray[shortestColumn] floatValue]); // 適才放了一個item上去,那末此時此刻哪一列的高度比擬低呢 for (int i = 0; i < _numberOfColumns; i++) { //以後列的高度(適才添加item的那一列) CGFloat currentHeight = [columnHeightArray[shortestColumn] floatValue]; // 掏出第i列中寄存列高度 CGFloat height = [columnHeightArray[i] floatValue]; if (currentHeight > height) { //第i列高度(height)最低時,高度最低的列(shortestColumn)固然就是第i列了 shortestColumn = i; } } } // 思慮下只應用上邊的代碼會湧現甚麼成績 // 其實不能影響心境,請不要驚恐... // 提醒:這個辦法會被屢次挪用,數組 }
---難點曾經停止---
沒有懂得的同伙請重點看上邊的難點辦法.
必需重寫的第二個辦法
// 2.前往的是, 每一個item對應的結構屬性 - (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect { return _attributesArray; }
必需重寫的第三個辦法
// 3.前往CollectionView的轉動規模 - (CGSize)collectionViewContentSize { return CGSizeMake(0, _contentHeight); }
ViewController裡邊關於CollectionView的創立和協定辦法就沒甚麼好說的了.
看下自界說類CustomCollectionViewLayout的創立和屬性的賦值情形:
CustomCollectionViewLayout *layout = [[CustomCollectionViewLayout alloc] init]; layout.numberOfColumns = 2;/**< 在ViewController裡設置瀑布流的列數,2列或3列為最好 */ layout.delegate = self;/**< 指定VC為盤算高度協定辦法的署理人 */
再看下協定辦法的完成部門(在ViewController.m中完成)
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout width:(CGFloat)width heightForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { UIImage *image = _imagesArray[indexPath.row]; // 依據傳過去的寬度來設置一個適合的矩形, 高度設為CGFLOAT_MAX表現以寬度來盤算高度 CGRect boundingRect = CGRectMake(0, 0, width, CGFLOAT_MAX); // 經由過程體系函數來獲得終究的矩形,須要引入頭文件 // #import <AVFoundation/AVFoundation.h> CGRect imageCurrentRect = AVMakeRectWithaspectRatioInsideRect(image.size, boundingRect); return imageCurrentRect.size.height; }
總結
到這裡呢,在IOS完成瀑布流就算是停止了,有興致的同伙可以本身著手試一下,願望本文對年夜家開辟IOS有所贊助。
【詳解IOS中若何完成瀑布流後果】的相關資料介紹到這裡,希望對您有所幫助! 提示:不會對讀者因本文所帶來的任何損失負責。如果您支持就請把本站添加至收藏夾哦!