1. 程式人生 > >自定義UICollectionViewLayout實現瀑布流

自定義UICollectionViewLayout實現瀑布流

該瀑布流的列數,列與列,行與行,距離四周的間距均通過代理由外界傳入

//
//  ViewController.m
//  PuBuFlow
//
//  Created by hq on 16/5/11.
//  Copyright © 2016年 hanqing. All rights reserved.
//

#import "ViewController.h"
#import "HQFlowLayout.h"
#import "HQCollectionViewCell.h"
#import <MJRefresh.h>
#import <MJExtension.h>
#import "HQShop.h"

@interface ViewController () <UICollectionViewDataSource,HQFlowLayoutDelegate>

@property(nonatomic,strong) NSMutableArray *goodsArrays;

@property(nonatomic,weak) UICollectionView *collectionView;


@end

static NSString * const 
[email protected]
"flow_cell"; @implementation ViewController -(NSMutableArray *)goodsArrays{ if (_goodsArrays==nil) { _goodsArrays=[NSMutableArray array]; } return _goodsArrays; } - (void)viewDidLoad { [super viewDidLoad]; [self setUpCollection]; [self setUpRefresh]; } -(void) setUpCollection{ HQFlowLayout *flow=[[HQFlowLayout alloc]init]; flow.delegate=self; UICollectionView *collectionView=[[UICollectionView alloc]initWithFrame:self.view.frame collectionViewLayout:flow]; collectionView.backgroundColor=[UIColor whiteColor]; collectionView.dataSource=self; [collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([HQCollectionViewCell class]) bundle:nil] forCellWithReuseIdentifier:cellID]; [self.view addSubview:collectionView]; self.collectionView=collectionView; } -(void) setUpRefresh{ //建立下拉重新整理 self.collectionView.mj_header=[MJRefreshNormalHeader headerWithRefreshingTarget:self refreshingAction:@selector(loadNewData)]; [self.collectionView.mj_header beginRefreshing]; //建立上拉重新整理 self.collectionView.mj_footer=[MJRefreshAutoNormalFooter footerWithRefreshingTarget:self refreshingAction:@selector(loadMoreData)]; } -(void) loadNewData{ [self.goodsArrays removeAllObjects]; NSMutableArray *array=[HQShop mj_objectArrayWithFilename:@"1.plist"]; [self.goodsArrays addObjectsFromArray:array]; [self.collectionView reloadData]; [self.collectionView.mj_header endRefreshing]; } -(void) loadMoreData{ NSMutableArray *array=[HQShop mj_objectArrayWithFilename:@"1.plist"]; [self.goodsArrays addObjectsFromArray:array]; [self.collectionView reloadData]; [self.collectionView.mj_footer endRefreshing]; } -(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{ return self.goodsArrays.count; } -(UICollectionViewCell *) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ HQShop *shop=self.goodsArrays[indexPath.item]; HQCollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:cellID forIndexPath:indexPath]; cell.shop=shop; return cell; } #pragma mark 我們自定義的瀑布流HQFlowLayout當中的代理實現方法 //設定每個cell的高度 -(CGFloat)flowLayout:(HQFlowLayout *)flowLayout heightForItemAtIndex:(NSInteger)index itemWidth:(CGFloat)itemWidth{ HQShop *shop=self.goodsArrays[index]; //返回高度 return shop.h*itemWidth/shop.w; } //設定cell的列數 -(CGFloat)columNumbersFlowLayout:(HQFlowLayout *)flowLayout{ return 3; } //設定行與行之間的間距 -(CGFloat)rowMarginFlowLayout:(HQFlowLayout *)flowLayout{ return 10; } //設定列與列之間的間距 -(CGFloat)colMarginFlowLayout:(HQFlowLayout *)flowLayout{ return 10; } //設定四周邊緣的距離 -(UIEdgeInsets)edgeIndsetsFlowLayout:(HQFlowLayout *)flowLayout{ UIEdgeInsets sets=UIEdgeInsetsMake(10, 10, 10, 10); return sets; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; } @end


核心方法如下

//
//  HQFlow.h
//  PuBuFlow
//
//  Created by hq on 16/5/11.
//  Copyright © 2016年 hanqing. All rights reserved.
//

#import <UIKit/UIKit.h>
@class HQFlowLayout;

@protocol HQFlowLayoutDelegate <NSObject>

@required

//返回每行的高度
-(CGFloat) flowLayout:(HQFlowLayout *) flowLayout heightForItemAtIndex:(NSInteger) index itemWidth:(CGFloat) itemWidth;

@optional
//返回列數
-(CGFloat) columNumbersFlowLayout:(HQFlowLayout *) flowLayout;

//返回行與行之間的間距
-(CGFloat) rowMarginFlowLayout:(HQFlowLayout *) flowLayout;

//返回列與列之間的間距
-(CGFloat) colMarginFlowLayout:(HQFlowLayout *) flowLayout;

//設定距離邊緣四周的距離
-(UIEdgeInsets) edgeIndsetsFlowLayout:(HQFlowLayout *) flowLayout;

@end


@interface HQFlowLayout : UICollectionViewLayout


@property(nonatomic,weak) id<HQFlowLayoutDelegate> delegate;


@end



//
//  HQFlow.m
//  PuBuFlow
//
//  Created by hq on 16/5/11.
//  Copyright © 2016年 hanqing. All rights reserved.
//

#import "HQFlowLayout.h"
#import <MJExtension.h>
#import <MJRefresh.h>

@interface HQFlowLayout()

@property(nonatomic,strong) NSMutableArray *dataArrays;

@property(nonatomic,strong) NSMutableArray *colHeightArrays;

@end

@implementation HQFlowLayout

//有3列
static NSInteger colNumber=3;

//每行之間的間距
static CGFloat rowMargin=10;

//每列之間的間距
static CGFloat colMargin=10;

//距離邊緣的間距
static UIEdgeInsets boderInsets={10,10,10,10};

#pragma mark 懶載入

-(NSMutableArray *)dataArrays{
    
    if (_dataArrays==nil) {
        _dataArrays=[NSMutableArray array];
    }
    return _dataArrays;
}

//儲存每行的高度
-(NSMutableArray *)colHeightArrays{
    
    if (_colHeightArrays==nil) {
        _colHeightArrays=[NSMutableArray array];
    }
    return _colHeightArrays;
}

#pragma mark 通過代理獲取屬性,獲取不到,則使用預設值

//獲取列數
-(NSInteger) getColumNumber{
    
    if ([self.delegate respondsToSelector:@selector(columNumbersFlowLayout:)]) {
        
        return [self.delegate columNumbersFlowLayout:self];
    }
    
    //沒有設定則用預設值
    return colNumber;
}

//獲取行與行之間的間距
-(CGFloat) getRowMargin{
    
    if ([self.delegate respondsToSelector:@selector(rowMarginFlowLayout:)]) {
        
        return [self.delegate rowMarginFlowLayout:self];
    }
    
    //沒有設定則用預設值
    return rowMargin;
    
}


//獲取列與列之間的間距
-(CGFloat) getColMargin{
    
    if ([self.delegate respondsToSelector:@selector(colMarginFlowLayout:)]) {
        
        return [self.delegate colMarginFlowLayout:self];
    }
    
    //沒有設定則用預設值
    return colMargin;
    
}

-(UIEdgeInsets) getEdgeInsets{
    
    if ([self.delegate respondsToSelector:@selector(edgeIndsetsFlowLayout:)]) {
        
        return [self.delegate edgeIndsetsFlowLayout:self];
    }
    
    //沒有設定則用預設值
    return boderInsets;
    
}



//初始化操作,必須寫super prepareLayout
//每次表格reloaddata,都會呼叫該方法
-(void)prepareLayout{
    
    [self.dataArrays removeAllObjects];
    
    [self.colHeightArrays removeAllObjects];
    
    [super prepareLayout];
    
     NSLog(@"%s",__func__);
    
    //初始化我們每個col的高度,預設為距離頂部的高度
    for (int i=0; i<[self getColumNumber]; i++) {
        
        [self.colHeightArrays addObject:@([self getEdgeInsets].top)];
    }
    
    NSInteger cellCount=[self.collectionView numberOfItemsInSection:0];
    
    //初始化我們所有cell屬性的陣列
    for (int i=0; i<cellCount; i++) {
        
        NSIndexPath *indexpath=[NSIndexPath indexPathForItem:i inSection:0];
        
        UICollectionViewLayoutAttributes *attr=[self layoutAttributesForItemAtIndexPath:indexpath];
        
        [self.dataArrays addObject:attr];
    }
}

//所有元素的屬性
//該方法,每滾動一次就會被呼叫一次,因此我們把陣列的初始化放到preparelayout當中去
-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{

    return self.dataArrays;
}

-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
    
    UICollectionViewLayoutAttributes *attr=[UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    
    CGFloat w=(self.collectionView.bounds.size.width-[self getColMargin]*([self getColumNumber]-1)-[self getEdgeInsets].left-[self getEdgeInsets].right)/[self getColumNumber];
    
//    CGFloat h=arc4random_uniform(100)+80;
    
    //通過代理方法獲取高度
    CGFloat h=[self.delegate flowLayout:self heightForItemAtIndex:indexPath.item itemWidth:w];
    
    //接下來計算哪個列最短
    
    CGFloat minHeight=[self.colHeightArrays[0] doubleValue];
    
    NSInteger minCol=0;
    
    for (int i=1; i<[self getColumNumber]; i++) {
        
        CGFloat currentHeight=[self.colHeightArrays[i] doubleValue];
        
        if (currentHeight<minHeight) {
            minCol=i;
            minHeight=currentHeight;
        }
    }

    CGFloat x=[self getEdgeInsets].left+(w+[self getColMargin])*minCol;
    
    CGFloat y=minHeight+[self getRowMargin];
    
    attr.frame=CGRectMake(x, y, w, h);
    
    self.colHeightArrays[minCol][email protected](CGRectGetMaxY(attr.frame));

    return attr;
    
}

-(CGSize)collectionViewContentSize{
    
   //取出我們的最大高度
    CGFloat maxHeight=[self.colHeightArrays[0] doubleValue];
    
    for (int i=1; i<[self getColumNumber]; i++) {
        
        CGFloat currentHeight=[self.colHeightArrays[i] doubleValue];
        
        if (currentHeight>maxHeight) {
            maxHeight=currentHeight;
        }
    }
    
    return CGSizeMake(0, maxHeight);
}


@end


相關推薦

no