iOS:UICollectionView純自定義的佈局:瀑布流佈局

建立瀑布流有三種方式:git

 
第一種方式:在一個ScrollView裏面放入三個單元格高度同樣的tableView,禁止tableView滾動,只需讓tableView隨着ScrollView滾動便可。這種方式太奇葩,不太推薦使用...
 
第二種方式:在一個ScrollView裏面從左到右依次放入三個UIView,當ScrollView滾動時,若是以前的三個view消失就將它們存入自定義的緩衝池,即數組中,下拉時再從數組中取出這三個view放到以前三個view位置的下面。可是,切記,每次要依次計算補全最短的,防止拉開的間距愈來愈大...,這種方式稍微麻煩一些…
 
第三種方式:其實就是上面第二種的簡單版,就是使用UICollectionView,由於它有本身的重用機制,咱們只須要作的就是計算下一次cell的位置便可....
 
 
集合視圖的自動佈局:UICollectionViewLayout是抽象根類,必須用它的子類才能建立實例,下面是重寫的方法,計算item的佈局屬性

//每一次從新佈局前,都會準備佈局(蘋果官方推薦使用該方法進行一些初始化)github

-(void)prepareLayout數組

 

//重寫layoutAttributesForItemAtIndexPath,返回每個item的佈局屬性(流式佈局內部已經幫助完成)佈局

-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPathatom

 

//是否要從新刷新佈局(只要顯示的item邊界發生改變就從新佈局)spa

//只要每一次從新佈局內部就會調用下面的layoutAttributesForElementsInRect:獲取全部cell(item)的屬性代理

-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBoundscode

 

//返回須要從新佈局的全部item屬性orm

-(NSArray*)layoutAttributesForElementsInRect:(CGRect)rectblog

 

🐷:下面的瀑布流佈局能夠直接拿走使用

 

下面使用第三種方式建立的瀑布流代碼以下:

WaterFlowLayout.h

#import <UIKit/UIKit.h>

/*
爲了體現封裝性的特色,咱們能夠把一些數據設置爲公共的,既能夠提升擴展性和通用性,
也便於外界按照本身的需求作必要的調整。
*/

@protocol WaterFlowLayoutDelegate; //設置代理傳遞數據,下降了與其餘類的耦合性,通用性更強


@class WaterFlowLayout;
@interface WaterFlowLayout : UICollectionViewLayout
@property (assign,nonatomic)CGFloat columnMargin;//每一列item之間的間距
@property (assign,nonatomic)CGFloat rowMargin;   //每一行item之間的間距
@property (assign,nonatomic)UIEdgeInsets sectionInset;//設置於collectionView邊緣的間距
@property (assign,nonatomic)NSInteger columnCount;//設置每一行排列的個數


@property (weak,nonatomic)id<WaterFlowLayoutDelegate> delegate; //設置代理
@end


@protocol WaterFlowLayoutDelegate
-(CGFloat)waterFlowLayout:(WaterFlowLayout *) WaterFlowLayout heightForWidth:(CGFloat)width andIndexPath:(NSIndexPath *)indexPath;
@end

WaterFloeLayout.m 

#import "WaterFlowLayout.h"

//每一列item之間的間距
//static const CGFloat columnMargin = 10;
//每一行item之間的間距
//static const CGFloat rowMargin = 10;

@interface WaterFlowLayout()
/** 這個字典用來存儲每一列item的高度 */
@property (strong,nonatomic)NSMutableDictionary *maxYDic;
/** 存放每個item的佈局屬性 */
@property (strong,nonatomic)NSMutableArray *attrsArray;
@end

@implementation WaterFlowLayout

/** 懶加載 */
-(NSMutableDictionary *)maxYDic
{
    if (!_maxYDic)
    {
        _maxYDic = [NSMutableDictionary dictionary];
    }
    return _maxYDic;
}

/** 懶加載 */
-(NSMutableArray *)attrsArray
{
    if (!_attrsArray)
    {
        _attrsArray = [NSMutableArray array];
    }
    return _attrsArray;
}

//初始化
-(instancetype)init
{
    if (self = [super init]){
        self.columnMargin = 10;
        self.rowMargin = 10;
        self.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10);
        self.columnCount = 3;
    }
    return self;
}

//每一次佈局前的準備工做
-(void)prepareLayout
{
    [super prepareLayout];
    
    //清空最大的y值
    for (int i =0; i < self.columnCount; i++)
    {
        NSString *column = [NSString stringWithFormat:@"%d",i];
        self.maxYDic[column] = @(self.sectionInset.top);
    }

    //計算全部item的屬性
    [self.attrsArray removeAllObjects];
    NSInteger count = [self.collectionView numberOfItemsInSection:0];
    for (int i=0; i<count; i++)
    {
        UICollectionViewLayoutAttributes *attrs = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
        
        [self.attrsArray addObject:attrs];
    }
}

//設置collectionView滾動區域
-(CGSize)collectionViewContentSize
{
    //假設最長的那一列爲第0列
    __block NSString *maxColumn = @"0";
    
    //遍歷字典,找出最長的那一列
    [self.maxYDic enumerateKeysAndObjectsUsingBlock:^(NSString *column, NSNumber *maxY, BOOL *stop) {
        
        if ([maxY floatValue] > [self.maxYDic[maxColumn] floatValue])
        {
            maxColumn = column;
        }
    }];
    return CGSizeMake(0, [self.maxYDic[maxColumn]floatValue]+self.sectionInset.bottom);
}

//容許每一次從新佈局
-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
    return YES;
}

//佈局每個屬性
-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
    //假設最短的那一列爲第0列
    __block NSString *minColumn = @"0";
    
    //遍歷字典,找出最短的那一列
    [self.maxYDic enumerateKeysAndObjectsUsingBlock:^(NSString *column, NSNumber *maxY, BOOL *stop) {
        
        if ([maxY floatValue] < [self.maxYDic[minColumn] floatValue])
        {
            minColumn = column;
        }
    }];
    
    //計算每個item的寬度和高度
    CGFloat width = (self.collectionView.frame.size.width - self.columnMargin*(self.columnCount - 1) - self.sectionInset.left - self.sectionInset.right) / self.columnCount;
    
    CGFloat height = [self.delegate waterFlowLayout:self heightForWidth:width andIndexPath:indexPath] ;
    
    
    //計算每個item的位置
    CGFloat x = self.sectionInset.left + (width + self.columnMargin) * [minColumn floatValue];
    CGFloat y = [self.maxYDic[minColumn] floatValue] + self.rowMargin;
    
    
    //更新這一列的y值
    self.maxYDic[minColumn] = @(y + height);
    
    
    //建立佈局屬性
    UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    
    //設置item的frame
    attrs.frame = CGRectMake(x, y, width, height);
    
    return attrs;
}

//佈局全部item的屬性,包括header、footer
-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
    return self.attrsArray;
}
@end

 

瀑布流演示結果以下:

 

github: https://github.com/xiayuanquan/XYQCollectionLayout.git

相關文章
相關標籤/搜索