起首是後果演示

特色:可以自在設置瀑布流的總列數(後果演示為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中若何完成瀑布流後果】的相關資料介紹到這裡,希望對您有所幫助! 提示:不會對讀者因本文所帶來的任何損失負責。如果您支持就請把本站添加至收藏夾哦!