该瀑布流的列数,列与列,行与行,距离四周的间距均通过代理由外界传入
//
// 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 cellID=@"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]=@(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