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
@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是最終item的frame
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