iOS自定義UICollectionViewLayout佈局實現瀑布流
ViewLayout.h 檔案:
#import <UIKit/UIKit.h>
@class ViewLayout
@protocol ViewLayoutDelegate <NSObject>
// 必須要實現的方法
@required
/** 返回 index位置的item的高 */
- (CGFloat)viewLayout:(ViewLayout *)ViewLayout heightForItemAtIndex:(NSInteger)index width:(CGFloat)width;
// 可選實現的方法
@optional
/** 返回 ViewLayout佈局的最大例數
- (CGFloat)numberOfMaxColumnInViewLayout:(ViewLayout *)viewLayout;
/** 返回 ViewLayout佈局每列的間距 */
- (CGFloat)numberOfColumnMarginInViewLayout:(ViewLayout *)viewLayout;
/** 返回 ViewLayout佈局的行間距 */
- (CGFloat)numberOfRowMarginInViewLayout:(ViewLayout *)viewLayout;
/** 返回 ViewLayout佈局的上左下右邊框間距 */
- (UIEdgeInsets)edgeInsetsOfEdgeInViewLayout:(ViewLayout *)viewLayout;
@end
@interface ViewLayout :UICollectionViewLayout
/** ViewLayout 代理屬性 */
@property (nonatomic,weak) id <ViewLayoutDelegate> delegate;
@end
ViewLayout.m 檔案:
#import "ViewLayout.h"
/** 預設最大例數 */
static constNSInteger defaultMaxColumn =3;
/** 預設例間距 */
static constCGFloat defaultdefaultColumnMargin =10;
/** 預設行間距 */
static constCGFloat defaultdefaultRowMargin =10;
/** 預設邊框間距 */
static constUIEdgeInsets defaultEdgeInsets = {10,10 ,10,10};
@interface ViewLayout ()
/** 裝有所有的佈局性的陣列 */
@property (nonatomic,strong) NSMutableArray *attributesArray;
/** 裝有所有有例的高度 */
@property (nonatomic,strong) NSMutableArray *columnHeights;
//方法宣告
- (CGFloat)maxColumn;
- (CGFloat)columnMargin;
- (CGFloat)rowMargin;
- (UIEdgeInsets)edgeInsets;
@end
@implementation ViewLayout
/** 返回最大列數方法實現*/
- (CGFloat)maxColumn{
if ([self.delegaterespondsToSelector:@selector(numberOfMaxColumnInViewLayout:)]) {
return [self.delegatenumberOfMaxColumnInViewLayout:self];
}else{
returndefaultMaxColumn;
}
}
/** 返回列間距方法實現*/
- (CGFloat)columnMargin{
if ([self.delegaterespondsToSelector:@selector(numberOfColumnMarginInViewLayout:)]) {
return [self.delegatenumberOfColumnMarginInViewLayout:self];
}else{
returndefaultdefaultColumnMargin;
}
}
/** 行間距方法實現*/
- (CGFloat)rowMargin{
if ([self.delegaterespondsToSelector:@selector(numberOfRowMarginInViewLayout:)]) {
return [self.delegatenumberOfRowMarginInViewLayout:self];
}else{
returndefaultdefaultRowMargin;
}
}
/** 邊框的間距方法實現*/
- (UIEdgeInsets)edgeInsets{
if ([self.delegaterespondsToSelector:@selector(edgeInsetsOfEdgeInViewLayout:)]) {
return [self.delegateedgeInsetsOfEdgeInViewLayout:self];
}else{
returndefaultEdgeInsets;
}
}
- (NSMutableArray *)attributesArray{
if (!_attributesArray) {
_attributesArray = [NSMutableArrayarray];
}
return_attributesArray;
}
- (NSMutableArray *)columnHeights{
if (!_columnHeights) {
_columnHeights = [NSMutableArrayarray];
}
return_columnHeights;
}
// 準備開始佈局時呼叫方法
- (void)prepareLayout{
[superprepareLayout];
[self.columnHeightsremoveAllObjects];
[self.attributesArrayremoveAllObjects];
//先初始給裝有所有例高陣列賦值
for (int i =0; i < self.maxColumn; ++i) {
self.columnHeights[i] =@(self.edgeInsets.top);
}
//獲取第總共的cell數量
NSInteger count = [self.collectionViewnumberOfItemsInSection:0];
//有 for迴圈為每為個 cell添加布局屬性
for (int i =0; i < count; ++i) {
//建立第 i個位置索引
NSIndexPath *indexPath = [NSIndexPathindexPathForItem:i inSection:0];
//根據索引建立佈局屬性
UICollectionViewLayoutAttributes *attributes = [selflayoutAttributesForItemAtIndexPath:indexPath];
[self.attributesArrayaddObject:attributes];
}
}
// 返回所有元素的佈局屬性陣列
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{
returnself.attributesArray;
}
// 返回索引 indexPath位置的cell的布屬性
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributeslayoutAttributesForCellWithIndexPath:indexPath];
CGFloat width =self.collectionView.bounds.size.width;
CGFloat w = (width -self.edgeInsets.left -self.edgeInsets.right - ((self.maxColumn - 1) * self.columnMargin)) /self.maxColumn;
// 執行代理方法拿到代理方法返回的高度
CGFloat h = [self.delegateviewLayout:selfheightForItemAtIndex:indexPath.itemwidth:w];
// 找出最短的那一例的高和例號
CGFloat miniHeight = [self.columnHeights[0]doubleValue]; //先初始預設陣列中第0個元素最小值
NSInteger miniColumn =0; //初始預設最小例號
for (int i =1; i < self.maxColumn; ++i) {
CGFloat height = [self.columnHeights[i]doubleValue];
if (miniHeight > height) {
miniHeight = height;
miniColumn = i;
}
}
CGFloat x =self.edgeInsets.left + miniColumn * (w +self.columnMargin);
CGFloat y = miniHeight;
if (y !=self.edgeInsets.top) {
y += self.rowMargin;
}
attributes.frame =CGRectMake(x, y, w, h);
//儲存更新當前高到對應例的陣列
self.columnHeights[miniColumn] =@(CGRectGetMaxY(attributes.frame));
return attributes;
}
// collectionView的滾動範圍
- (CGSize)collectionViewContentSize{
//找出最高的所在例
CGFloat maxHeight =0; //初始最大高為 0
for (int i =0; i < self.maxColumn; ++i) {
CGFloat height = [self.columnHeights[i]doubleValue];
if (maxHeight < height) {
maxHeight = height;
}
}
returnCGSizeMake(0, maxHeight +self.edgeInsets.bottom);
}
@end