ZYXWaterflowView.h
//
// ZYXWaterflowView.h
// waterflow-custom
//
// 使用瀑布流布局展示内容的控件
//
// Created by zhaoyingxin on 15/9/5.
// Copyright © 2014年 zhaoyingxin@aliyun.com. All rights reserved.
//
#import <UIKit/UIKit.h>
@class ZYXWaterflowView,ZYXWaterflowViewCell;
#pragma mark - ZYXWaterflowViewDataSource
@protocol ZYXWaterflowViewDataSource <NSObject>
@required
/**
* 一共有多少个瀑布流的方格子
*/
- (NSUInteger)numberOfCellsInWaterflowView:(ZYXWaterflowView *)waterflowView;
/**
* 返回index对应位置的瀑布流方格子Cell
*/
- (ZYXWaterflowViewCell *)waterflowView:(ZYXWaterflowView *)waterflowView cellAtIndex:(NSUInteger)index;
@optional
/**
* 瀑布流布局的列数
*/
- (NSUInteger)numberOfColumnsInWaterflowView:(ZYXWaterflowView *)waterflowView;
@end
#pragma mark - ZYXWaterflowViewDelegate
// 间距
typedef enum{
ZYXWaterflowViewMarginTypeTop,
ZYXWaterflowViewMarginTypeBottom,
ZYXWaterflowViewMarginTypeLeft,
ZYXWaterflowViewMarginTypeRight,
ZYXWaterflowViewMarginTypeColumn,
ZYXWaterflowViewMarginTypeRow
} ZYXWaterflowViewMarginType;
@protocol ZYXWaterflowViewDelegate <UIScrollViewDelegate>
@optional
/**
* index位置Cell对应的高度
*/
- (CGFloat)waterflowView:(ZYXWaterflowView *)waterflowView heightAtIndex:(NSUInteger)index;
/**
* 选中index位置的Cell
*/
- (void)waterflowView:(ZYXWaterflowView *)waterflowView didSelectAtIndex:(NSUInteger)index;
/**
* 返回间距
*/
- (CGFloat)waterflowView:(ZYXWaterflowView *)waterflowView marginForType:(ZYXWaterflowViewMarginType)type;
@end
@interface ZYXWaterflowView : UIScrollView
// 数据源
@property (nonatomic,weak) id<ZYXWaterflowViewDataSource>dataSource;
// 代理
@property (nonatomic,weak) id<ZYXWaterflowViewDelegate>delegate;
- (void)reloadData;
@end
ZYXWaterflowView.m
//
// ZYXWaterflowView.m
// waterflow-custom
//
// Created by zhaoyingxin on 15/9/5.
// Copyright © 2014年 zhaoyingxin@aliyun.com. All rights reserved.
//
#import "UIView+Extension.h"
#import "ZYXWaterflowView.h"
#define ZYXWaterflowViewDefaultCellH 70
#define ZYXWaterflowViewDefaultMargin 8
#define ZYXWaterflowViewDefaultNumberOfColumns 3
#import "ZYXWaterflowViewCell.h"
@implementation ZYXWaterflowView
/**
* 刷新数据 计算每个Cell的frame
*/
-(void)reloadData
{
// Cell的总数
int numberOfCells = (int)[self.dataSource numberOfCellsInWaterflowView:self]; // 200个Cell
// Cell排布的总列数
int numberOfColumns = (int)[self numberOfColumns]; // 3列
// 间距
CGFloat topM = [self marginForType:ZYXWaterflowViewMarginTypeTop]; // 10
CGFloat bottomM = [self marginForType:ZYXWaterflowViewMarginTypeBottom]; // 10
CGFloat leftM = [self marginForType:ZYXWaterflowViewMarginTypeLeft]; // 10
CGFloat rightM = [self marginForType:ZYXWaterflowViewMarginTypeRight]; // 10
CGFloat columnM = [self marginForType:ZYXWaterflowViewMarginTypeColumn]; // 5
CGFloat rowM = [self marginForType:ZYXWaterflowViewMarginTypeRow]; // 5
// cell 的宽度
CGFloat cellW = (self.width-leftM-rightM-columnM*(numberOfColumns-1))/numberOfColumns;
// 用一个C语言数组存放着所有列的最大值
CGFloat maxYOfColumns[numberOfColumns]; // 3列
for (int i=0; i<numberOfColumns; i++) {
maxYOfColumns[i] = 0.0f;
}
for (int i=0; i<numberOfCells; i++) { // 200个Cell
// cell 处在第几列 应该把新的Cell 放在Y值最小的那列
NSUInteger cellColumn = 0; // 默认放在第0列
// cell 所处那列的Y的最大值
CGFloat maxYOfCellColumn = maxYOfColumns[cellColumn];
// 求出新Cell应该所处的Y的最小的那列
for (int j=1; j<numberOfColumns; j++) {
if (maxYOfColumns[j] < maxYOfCellColumn) {
cellColumn = j; // 计算出Cell应处的列的序号
maxYOfCellColumn = maxYOfColumns[j]; // Cell应处的列的Y值
}
}
// 询问代理i位置的高度
CGFloat cellH = [self heightAtIndex:i]; // i%3 0~70 1~100 2~90
// cell 的位置
CGFloat cellX = leftM + cellColumn*(cellW + columnM);
CGFloat cellY = 0.0f;
if (maxYOfCellColumn == 0.0) { // 首行
cellY = topM;
} else {
cellY = maxYOfCellColumn + rowM;
}
CGRect cellFrame = CGRectMake(cellX, cellY, cellW, cellH);
// 更新最短那列Y值
maxYOfColumns[cellColumn] = CGRectGetMaxY(cellFrame);
// 显示Cell
ZYXWaterflowViewCell *cell = [self.dataSource waterflowView:self cellAtIndex:i];
cell.frame = cellFrame;
#warning (zyx-3)显示瀑布流的方格子
[self addSubview:cell];
}
}
#pragma mark - 私有方法
/**
* 数据源
* cell排布的列数 默认3列
*/
- (NSUInteger)numberOfColumns
{
if ([self.dataSource respondsToSelector:@selector(numberOfColumnsInWaterflowView:)]) {
return [self.dataSource numberOfColumnsInWaterflowView:self]; // 3
} else {
return ZYXWaterflowViewDefaultNumberOfColumns; // 3
}
}
/**
* 代理
*/
- (CGFloat)marginForType:(ZYXWaterflowViewMarginType)type
{
if ([self.delegate respondsToSelector:@selector(waterflowView:marginForType:)]) {
return [self.delegate waterflowView:self marginForType:type]; // 上下左右 10 ,其他5
} else {
return ZYXWaterflowViewDefaultMargin; // 默认全是8
}
}
- (CGFloat)heightAtIndex:(NSUInteger)index
{
if ([self.delegate respondsToSelector:@selector(waterflowView:heightAtIndex:)]) {
return [self.delegate waterflowView:self heightAtIndex:index];
} else {
return ZYXWaterflowViewDefaultCellH;
}
}
@end
ZYXWaterflowViewCell.h
//
// ZYXWaterflowViewCell.h
// waterflow-custom
//
// Created by zhaoyingxin on 15/9/5.
// Copyright © 2014年 zhaoyingxin@aliyun.com. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface ZYXWaterflowViewCell : UIView
@end
ZYXWaterflowViewCell.m
#import "ZYXWaterflowViewCell.h"
@implementation ZYXWaterflowViewCell
@end
ViewController.m
#define ZYXColor(r,g,b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1.0]
#define ZYXColorRGBA(r,g,b,a) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:a]
#define ZYXRandomColor ZYXColor(arc4random_uniform(256),arc4random_uniform(256),arc4random_uniform(256))
#import "ViewController.h"
#import "ZYXWaterflowView.h"
#import "ZYXWaterflowViewCell.h"
@interface ViewController () <ZYXWaterflowViewDataSource,ZYXWaterflowViewDelegate>
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
ZYXWaterflowView *waterflowView = [[ZYXWaterflowView alloc] init];
waterflowView.scrollEnabled = YES;
waterflowView.userInteractionEnabled = YES;
waterflowView.frame = self.view.bounds;
waterflowView.dataSource = self;
waterflowView.delegate = self;
[self.view addSubview:waterflowView];
[waterflowView reloadData];
}
#pragma mark - ZYXWaterflowViewDataSource 数据源方法
- (NSUInteger)numberOfCellsInWaterflowView:(ZYXWaterflowView *)waterflowView
{
return 2000;
}
- (NSUInteger)numberOfColumnsInWaterflowView:(ZYXWaterflowView *)waterflowView
{
return 3;
}
- (ZYXWaterflowViewCell *)waterflowView:(ZYXWaterflowView *)waterflowView cellAtIndex:(NSUInteger)index
{
ZYXWaterflowViewCell *cell = [[ZYXWaterflowViewCell alloc] init];
cell.backgroundColor = ZYXRandomColor;
return cell;
}
#pragma mark - ZYXWaterflowViewDelegate 代理方法
- (CGFloat)waterflowView:(ZYXWaterflowView *)waterflowView heightAtIndex:(NSUInteger)index
{
switch (index % 3) {
case 0:
return 70;
break;
case 1:
return 100;
break;
case 2:
return 90;
break;
default:
return 110;
break;
}
}
- (CGFloat)waterflowView:(ZYXWaterflowView *)waterflowView marginForType:(ZYXWaterflowViewMarginType)type
{
switch (type) {
case ZYXWaterflowViewMarginTypeTop:
case ZYXWaterflowViewMarginTypeBottom:
case ZYXWaterflowViewMarginTypeLeft:
case ZYXWaterflowViewMarginTypeRight:
return 10;
break;
default:
return 5;
break;
}
}
- (void)waterflowView:(ZYXWaterflowView *)waterflowView didSelectAtIndex:(NSUInteger)index
{
NSLog(@"点击了 %d 个Cell",(int)index);
}
@end