1. 程式人生 > >iOS瀑布流佈局實現

iOS瀑布流佈局實現

最近開發中遇到了關於瀑布流佈局的需求,所有就整理了一個瀑布流佈局類,使用時只需要調整列數、行間距、列間距、上下左右邊緣就可以做出各種需求的瀑布流佈局,下面直接上程式碼:

自定義瀑布流需要繼承UICollectionViewLayout佈局類

.h檔案

#import <UIKit/UIKit.h>

@interface ZYYWaterLayout :UICollectionViewLayout

@end


.m檔案

#import "ZYYWaterLayout.h"

//預設的列數

staticconstCGFloat ZYYCollumCoutnt =3;

//列間距

staticconstCGFloat ZYYCollumMargin =10;

//行間距

staticconstCGFloat ZYYRowMargin =10;

//邊緣間距

staticconstUIEdgeInsets ZYYEdgeUnsets = {10,10,10,10};

@interfaceZYYWaterLayout()

//用於存放cell屬性的陣列

@property (strong,nonatomic)NSMutableArray *attrsArray;

//用於存放所有列高度陣列

@property (strong,nonatomic)NSMutableArray

*maxH;

@end

@implementation ZYYWaterLayout

//懶載入屬性陣列

- (NSMutableArray *)attrsArray{

if (_attrsArray ==nil) {

_attrsArray = [NSMutableArrayarray];

    }

return_attrsArray;

}

//懶載入高度屬性陣列

- (NSMutableArray *)maxH{

if (_maxH ==nil) {

_maxH = [NSMutableArrayarray];

    }

return_maxH;

}

//準備佈局每次重新整理都會呼叫此方法

- (void)prepareLayout{

    [superprepareLayout];

//先清除以前計算的所有高度,這種做法比較嚴謹,如果有下拉重新整理,不及時清空陣列的話會造成資料混亂

    [self.maxHremoveAllObjects];

//這裡先將數組裡面的初始值設為0

for (NSInteger i =0; i < ZYYCollumCoutnt; i ++) {

        [self.maxHaddObject:@0];

    }

NSLog(@"%s",__func__);

//清除以前的所有屬性

    [self.attrsArrayremoveAllObjects];

//開始建立每個cell對應的佈局屬性

//1、獲取collectionView裡面的有多少個item

NSInteger count = [self.collectionViewnumberOfItemsInSection:0];

//建立多少collectionViewcell屬性

for (NSInteger i=1; i<count; i++) {

//獲取item對應的indexPath

NSIndexPath *indexPath = [NSIndexPathindexPathForItem:i inSection:0];

//建立屬性呼叫下面的layoutAttributesForItemAtIndexPath方法

UICollectionViewLayoutAttributes *attrs = [selflayoutAttributesForItemAtIndexPath:indexPath];

//設定cell的屬性直接呼叫layoutAttributesForItemAtIndexPath方法即可

        [self.attrsArrayaddObject:attrs];

    }

}

/**

 * 決定佈局的關鍵所在

 *

 *  @param rect 屬性rect

 *

 *  @return 返回屬性陣列

 */

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{

NSLog(@"%s",__func__);

returnself.attrsArray;

}

/**

 *  返回indexPath位置cell對應的佈局屬性

 * 這個方法是核心演算法

 */

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{

//建立屬性

UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributeslayoutAttributesForCellWithIndexPath:indexPath];

//collectionView的寬度

CGFloat collectionViewW =self.collectionView.frame.size.width;

//列號

NSInteger cloumIndex =0;

//預設第一行是最小的,這樣做的話可以讓下面的for迴圈從i=1開始遍歷,這樣做可以優化效能

CGFloat minClumnHeight = [self.maxH[0]doubleValue];

for (NSInteger i =1; i < ZYYCollumCoutnt; i++) {

//取出第i列元素的y

CGFloat cheight = [self.maxH[i]doubleValue];

if (minClumnHeight > cheight) {

            minClumnHeight = cheight;

            cloumIndex = i;

        }

    }

//每個item的寬度 == collectionView的寬度 -左邊距 -右邊距 -(列數-1*間距)再除於列數

CGFloat w = (collectionViewW -ZYYEdgeUnsets.left -ZYYEdgeUnsets.right - (ZYYCollumCoutnt -1) * ZYYCollumMargin)/3.0;

//高度這裡用的是隨機數,做專案時根據的是素材的高度

CGFloat h =50 + arc4random_uniform(100);

//x可以根據列來算

CGFloat x =ZYYEdgeUnsets.left + cloumIndex * (ZYYRowMargin + w);

//y最小itme值計算

CGFloat y = minClumnHeight +ZYYRowMargin;

//設定佈局屬性的frame,這個frame是最終itemframe

     attrs.frame =CGRectMake(x, y, w, h);

//更新最短那列的高度

self.maxH[cloumIndex] =@(CGRectGetMaxY(attrs.frame));

return attrs;

}

//尺寸

- (CGSize)collectionViewContentSize{

//找出y值最大的的那一列,和上面找出最小高度相似

CGFloat maxColunmHeight = [self.maxH[0]doubleValue];

for (NSInteger i =1; i < ZYYCollumCoutnt; i++) {

CGFloat my = [self.maxH[i]doubleValue];

if (maxColunmHeight < my) {

            maxColunmHeight = my;

        }

    }

returnCGSizeMake(0, maxColunmHeight +ZYYEdgeUnsets.bottom);

}

結語:上面的註釋比較清楚,用的時候直接將程式碼複製貼上就可以使用了

@end