瀑布流

一、瀑布流設(shè)計(jì)方案

不可取.png

過于復(fù)雜.png

最優(yōu)方案.png

二、瀑布流設(shè)計(jì)思路分析

1、自定義流水布局中,指定滾動(dòng)方向、默認(rèn)列數(shù)、行間距、列間距、以及指定cell的大小itemSize

2、可以提供一個(gè)數(shù)組columnMaxYs(記錄當(dāng)前每一列的最大Y值),假如3列,我們就提供一個(gè)3個(gè)元素的數(shù)組,記錄所有布局屬性

columnMaxYs實(shí)現(xiàn)懶加載,

2.并在prepareLayout方法中 :

1.先將columnMaxYs清空。

2.再進(jìn)行初始化每個(gè)元素為0.

3.獲取所有的Cell的布局屬性,而每一個(gè)Cell的布局屬性通過調(diào)用layoutAttributesForItemAtIndexPath:方式獲取,而調(diào)用該方法,就會(huì)執(zhí)行第4步

(至于為什么在prepareLayout方法中初始化,而不是在init方法初始化:是因?yàn)?,該方法每次刷新都?huì)調(diào)用,而init方法中只會(huì)在創(chuàng)建布局對(duì)象的時(shí)候只執(zhí)行一次,例如:如果進(jìn)行下拉刷新最新數(shù)據(jù)的時(shí)候,需求重新初始化數(shù)據(jù),而如果我們使用的是init方法的話,并不會(huì)調(diào)用也就并不會(huì)清除之前的然后初始化,而使用該方法prepareLayout可以辦到,因?yàn)樗鼤?huì)再次調(diào)用,而init不會(huì)調(diào)用)

3.獲取所有Cell的布局屬性,

注意:對(duì)與所有Cell的布局屬性,在第一次加載的時(shí)候需要計(jì)算一次,而當(dāng)刷新collectionView的時(shí)候,當(dāng)然也需要重新計(jì)算:所以我們提供一個(gè)布局屬性的數(shù)組,來保存所有Cell的布局刷新,避免不必要的計(jì)算。 ——> 放在哪? 計(jì)算最好呢?? ———>? 首選放在prepareLayout方法中,因?yàn)樗鼤?huì)調(diào)用一次加載,而且當(dāng)刷新的時(shí)候也會(huì)調(diào)用,滿足需求,我們先將之前的全部移除,然后重新返回最新的布局屬性數(shù)組; 但是,最好不要放在layoutAttributesForElementsInRect:方法(返回所有元素的布局屬性數(shù)組中),因?yàn)楦姆椒ㄔ跐L動(dòng)collectionView的時(shí)候,會(huì)頻繁的調(diào)用,比較銷毀性能。

3、在layoutAttributesForElementsInRect:方法(返回所有元素的布局屬性數(shù)組 )

返回之前保存的所有Cell的布局屬性數(shù)組

4、我們可以在layoutAttributesForItemAtIndexPath: 方法: 來調(diào)整 Cell的布局屬性 , 指定Cell的 frame

1.在該方法中拿到當(dāng)前cell的默認(rèn)布局屬性attrs,進(jìn)行下面的調(diào)整,就可以實(shí)現(xiàn)瀑布流了2.遍歷columnMaxYs數(shù)組,需要找出最短一列的 列號(hào) 與 最大Y值3. 確定當(dāng)前Cell的 存放的x.y位置 以及widht與height? ? ? —> width:根據(jù)屏幕寬度與列數(shù)以及每列的寬度求出.? height:服務(wù)器返回的? ? ? —> x:需要根據(jù)當(dāng)前最短一列的列號(hào)與Cell的寬度與間距可以求出來;y:可以根據(jù)當(dāng)前最短一列的最大Y值 + 行間距可以求出4.重新設(shè)置修改當(dāng)前Cell的布局屬性attrs 的 frame即可?!?gt; 之前已經(jīng)拿到當(dāng)前Cell的 默認(rèn)布局屬性,以及上一步已經(jīng)獲取到當(dāng)前Cell需要存放的x.y位置后,5.將修改Cell布局屬性之后的,當(dāng)前列當(dāng)前Cell的Y值最大,所有我們要將該值記錄到數(shù)組columnMaxYs中,以便下次對(duì)比

5、注意:我們需要設(shè)置collectionView的contentSize,它才會(huì)滾動(dòng),那么我們?nèi)绾卧O(shè)置呢?

——> 在定義布局類中,系統(tǒng)提供了一個(gè)collectionViewContentSize的get對(duì)象方法(決定collectionView的contentSize)? ? ? ? ? ? ? ? ? —> contentSize的高度為:計(jì)算出最長那一列的最大Y值,也就是columnMaxYs的最大值 + 行間距

三、瀑布流的基本實(shí)現(xiàn)

效果圖.png

1.創(chuàng)建一個(gè)控制器JPCollectionViewController,繼承UICollectionViewController,使用我們自定義的流水布局JPWaterflowLayout(實(shí)現(xiàn)見其后)

#import"JPCollectionViewController.h"#import"JPWaterflowLayout.h"http:// 自定義流水布局@interfaceJPCollectionViewController()@end@implementationJPCollectionViewControllerstaticNSString*constreuseIdentifier =@"cellID";- (void)viewDidLoad {? ? [superviewDidLoad];// 切換布局self.collectionView.collectionViewLayout = [[JPWaterflowLayout alloc] init];}#pragma mark- (NSInteger)collectionView:(UICollectionView*)collectionView numberOfItemsInSection:(NSInteger)section {return30;}- (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView cellForItemAtIndexPath:(NSIndexPath*)indexPath {UICollectionViewCell*cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];? ? cell.backgroundColor = [UIColororangeColor];returncell;}@end

2.自定義流水布局JPWaterflowLayout,繼承UICollectionViewLayout

#import"JPWaterflowLayout.h"#define JPCollectionW self.collectionView.frame.size.width/** 每一行之間的間距 */staticconstCGFloatJPDefaultRowMargin =10;/** 每一列之間的間距 */staticconstCGFloatJPDefaultColumnMargin =10;/** 每一列之間的間距 top, left, bottom, right */staticconstUIEdgeInsetsJPDefaultInsets = {10,10,10,10};/** 默認(rèn)的列數(shù) */staticconstintJPDefaultColumsCount =3;@interfaceJPWaterflowLayout()/** 每一列的最大Y值 */@property(nonatomic,strong)NSMutableArray*columnMaxYs;/** 存放所有cell的布局屬性 */@property(nonatomic,strong)NSMutableArray*attrsArray;@end@implementationJPWaterflowLayout#pragma mark - 懶加載- (NSMutableArray*)columnMaxYs{if(!_columnMaxYs) {? ? ? ? _columnMaxYs = [[NSMutableArrayalloc] init];? ? }return_columnMaxYs;}- (NSMutableArray*)attrsArray{if(!_attrsArray) {? ? ? ? _attrsArray = [[NSMutableArrayalloc] init];? ? }return_attrsArray;}#pragma mark - 實(shí)現(xiàn)內(nèi)部的方法/**

* 決定了collectionView的contentSize

*/- (CGSize)collectionViewContentSize{// 找出最長那一列的最大Y值CGFloatdestMaxY = [self.columnMaxYs[0] doubleValue];for(NSUIntegeri =1; i

* 說明所有元素(比如cell、補(bǔ)充控件、裝飾控件)的布局屬性

*/- (NSArray*)layoutAttributesForElementsInRect:(CGRect)rect{returnself.attrsArray;}/**

* 說明cell的布局屬性

*/- (UICollectionViewLayoutAttributes*)layoutAttributesForItemAtIndexPath:(NSIndexPath*)indexPath{UICollectionViewLayoutAttributes*attrs = [UICollectionViewLayoutAttributeslayoutAttributesForCellWithIndexPath:indexPath];/** 計(jì)算indexPath位置cell的布局屬性 */// 水平方向上的總間距CGFloatxMargin = JPDefaultInsets.left + JPDefaultInsets.right + (JPDefaultColumsCount -1) * JPDefaultColumnMargin;// cell的寬度CGFloatw = (JPCollectionW - xMargin) / JPDefaultColumsCount;// cell的高度,測(cè)試數(shù)據(jù),隨機(jī)數(shù)CGFloath =50+ arc4random_uniform(150);// 找出最短那一列的 列號(hào) 和 最大Y值CGFloatdestMaxY = [self.columnMaxYs[0] doubleValue];NSUIntegerdestColumn =0;for(NSUIntegeri =1; i columnMaxY) {? ? ? ? ? ? destMaxY = columnMaxY;? ? ? ? ? ? destColumn = i;? ? ? ? }? ? }// cell的x值CGFloatx = JPDefaultInsets.left + destColumn * (w + JPDefaultColumnMargin);// cell的y值CGFloaty = destMaxY + JPDefaultRowMargin;// cell的frameattrs.frame =CGRectMake(x, y, w, h);// 更新數(shù)組中的最大Y值self.columnMaxYs[destColumn] = @(CGRectGetMaxY(attrs.frame));returnattrs;}@end

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容