iOS流佈局UICollectionView系列四——自定義FlowLayout進行瀑布流佈局

iOS流佈局UICollectionView系列四——自定義FlowLayout進行瀑布流佈局

1、引言

        前幾篇博客從UICollectionView的基礎應用到設置UICollectionViewFlowLayout更加靈活的進行佈局,但都限制在系統爲咱們準備好的佈局框架中,仍是有一些侷限性,例如,若是我要進行瀑布流似的不定高佈局,前面的方法就很難知足咱們的需求了,以下:數組

這種佈局無疑在app的應用中更加普遍,商品的展現,書架書目的展現,都會傾向於採用這樣的佈局方式,固然,經過自定義FlowLayout,咱們也很容易實現。app

2、進行自定義瀑布流佈局

        首先,咱們新建一個文件繼承於UICollectionViewFlowLayout:框架

@interface MyLayout : UICollectionViewFlowLayout

爲了演示的方面,這裏我不錯更多的封裝,添加一個屬性,直接讓外界將item個數傳遞進來,咱們把重心方法重寫佈局的方法上:dom

@interface MyLayout : UICollectionViewFlowLayout
@property(nonatomic,assign)int itemCount;
@end

前面說過,UICollectionViewFlowLayout是一個專門用來管理collectionView佈局的類,所以,collectionView在進行UI佈局前,會經過這個類的對象獲取相關的佈局信息,FlowLayout類將這些佈局信息所有存放在了一個數組中,數組中是UICollectionViewLayoutAttributes類,這個類是對item佈局的具體設置,之後我們在討論這個類。總之,FlowLayout類將每一個item的位置等佈局信息放在一個數組中,在collectionView佈局時,會調用FlowLayout類layoutAttributesForElementsInRect:方法來獲取這個佈局配置數組。所以,咱們須要重寫這個方法,返回咱們自定義的配置數組,另外,FlowLayout類在進行佈局以前,會調用prepareLayout方法,因此咱們能夠重寫這個方法,在裏面對咱們的自定義配置數據進行一些設置。佈局

簡單來講,自定義一個FlowLayout佈局類就是兩個步驟:atom

一、設計好咱們的佈局配置數據 prepareLayout方法中spa

二、返回咱們的配置數組 layoutAttributesForElementsInRect方法中設計

示例代碼以下:code

@implementation MyLayout
{
    //這個數組就是咱們自定義的佈局配置數組
    NSMutableArray * _attributeAttay;
}
//數組的相關設置在這個方法中
//佈局前的準備會調用這個方法
-(void)prepareLayout{
    _attributeAttay = [[NSMutableArray alloc]init];
    [super prepareLayout];
    //演示方便 咱們設置爲靜態的2列
    //計算每個item的寬度
    float WIDTH = ([UIScreen mainScreen].bounds.size.width-self.sectionInset.left-self.sectionInset.right-self.minimumInteritemSpacing)/2;
    //定義數組保存每一列的高度
    //這個數組的主要做用是保存每一列的總高度,這樣在佈局時,咱們能夠始終將下一個Item放在最短的列下面
    CGFloat colHight[2]={self.sectionInset.top,self.sectionInset.bottom};
    //itemCount是外界傳進來的item的個數 遍從來設置每個item的佈局
    for (int i=0; i<_itemCount; i++) {
        //設置每一個item的位置等相關屬性
        NSIndexPath *index = [NSIndexPath indexPathForItem:i inSection:0];
        //建立一個佈局屬性類,經過indexPath來建立
        UICollectionViewLayoutAttributes * attris = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:index];
        //隨機一個高度 在40——190之間
        CGFloat hight = arc4random()%150+40;
        //哪一列高度小 則放到那一列下面
        //標記最短的列
        int width=0;
        if (colHight[0]<colHight[1]) {
            //將新的item高度加入到短的一列
            colHight[0] = colHight[0]+hight+self.minimumLineSpacing;
            width=0;
        }else{
            colHight[1] = colHight[1]+hight+self.minimumLineSpacing;
            width=1;
        }
        
        //設置item的位置
        attris.frame = CGRectMake(self.sectionInset.left+(self.minimumInteritemSpacing+WIDTH)*width, colHight[width]-hight-self.minimumLineSpacing, WIDTH, hight);
        [_attributeAttay addObject:attris];
    }
    
    //設置itemSize來確保滑動範圍的正確 這裏是經過將全部的item高度平均化,計算出來的(以最高的列位標準)
    if (colHight[0]>colHight[1]) {
        self.itemSize = CGSizeMake(WIDTH, (colHight[0]-self.sectionInset.top)*2/_itemCount-self.minimumLineSpacing);
    }else{
          self.itemSize = CGSizeMake(WIDTH, (colHight[1]-self.sectionInset.top)*2/_itemCount-self.minimumLineSpacing);
    }
    
}
//這個方法中返回咱們的佈局數組
-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{
    return _attributeAttay;
}


@end

自定義完成FlowLayout後,咱們在ViewController中進行使用:orm

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    MyLayout * layout = [[MyLayout alloc]init];
    layout.scrollDirection = UICollectionViewScrollDirectionVertical;
    layout.itemCount=100;
     UICollectionView * collect  = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 0, 320, 400) collectionViewLayout:layout];
    collect.delegate=self;
    collect.dataSource=self;
    
    [collect registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"cellid"];
  
    [self.view addSubview:collect];
    
    
}



-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
    return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
    return 100;
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
    UICollectionViewCell * cell  = [collectionView dequeueReusableCellWithReuseIdentifier:@"cellid" forIndexPath:indexPath];
    cell.backgroundColor = [UIColor colorWithRed:arc4random()%255/255.0 green:arc4random()%255/255.0 blue:arc4random()%255/255.0 alpha:1];
    return cell;
}

運行效果就是咱們引言中的截圖。

3、UICollectionViewLayoutAttributes類中咱們能夠配置的屬性

        經過上面的例子,咱們能夠了解,collectionView的item佈局實際上是LayoutAttributes類具體配置的,這個類能夠配置的佈局屬性不止是frame這麼簡單,其中還有許多屬性:

//配置item的佈局位置
@property (nonatomic) CGRect frame;
//配置item的中心
@property (nonatomic) CGPoint center;
//配置item的尺寸
@property (nonatomic) CGSize size;
//配置item的3D效果
@property (nonatomic) CATransform3D transform3D;
//配置item的bounds
@property (nonatomic) CGRect bounds NS_AVAILABLE_IOS(7_0);
//配置item的旋轉
@property (nonatomic) CGAffineTransform transform NS_AVAILABLE_IOS(7_0);
//配置item的alpha
@property (nonatomic) CGFloat alpha;
//配置item的z座標
@property (nonatomic) NSInteger zIndex; // default is 0
//配置item的隱藏
@property (nonatomic, getter=isHidden) BOOL hidden; 
//item的indexpath
@property (nonatomic, strong) NSIndexPath *indexPath;
//獲取item的類型
@property (nonatomic, readonly) UICollectionElementCategory representedElementCategory;
@property (nonatomic, readonly, nullable) NSString *representedElementKind; 

//一些建立方法
+ (instancetype)layoutAttributesForCellWithIndexPath:(NSIndexPath *)indexPath;
+ (instancetype)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind withIndexPath:(NSIndexPath *)indexPath;
+ (instancetype)layoutAttributesForDecorationViewOfKind:(NSString *)decorationViewKind withIndexPath:(NSIndexPath *)indexPath;

經過上面的屬性,能夠佈局出各式各樣的炫酷效果,正如一句話:沒有作不到,只有想不到。

專一技術,熱愛生活,交流技術,也作朋友。

——琿少 QQ羣:203317592

相關文章
相關標籤/搜索