// MyWaterFlowView.h
// 瀑布流
//
// Created by Jose on 15-7-11.
// Copyright (c) 2015年 Jose. All rights reserved.
//
#import <UIKit/UIKit.h>
//枚举方法
typedef enum {
MyWaterFlowViewMarginTypeTop,
MyWaterFlowViewMarginTypeBottom,
MyWaterFlowViewMarginTypeLeft,
MyWaterFlowViewMarginTypeRight,
//每一列
MyWaterFlowViewMarginTypeColumn,
//没一行
MyWaterFlowViewMarginTypeRow
}MyWaterFlowViewMarginType;
@class MyWaterFlowView,MyWaterFlowViewCell;
/**
* 数据源方法
*/
@protocol MyWaterFlowViewDataSource <NSObject>
@required
// 一共有多少个数据
// NSUInteger是无符号类型,即没有负数
-(NSUInteger)NumberOfCellInWaterFlowView:(MyWaterFlowView *)mywaterflowview;
// 返回index位置对应的cell
-(MyWaterFlowViewCell *)WaterFlowViewCell:(MyWaterFlowView *)mywaterflowview CellAtIndex:(NSUInteger)index;
@optional
// 返回一共有多少列
-(NSUInteger)NumberOfColumsInWaterFlowView:(MyWaterFlowView *)mywateflowview;
@end
/**
* 代理方法
*/
@protocol MyWaterFlowViewDelegate <UIScrollViewDelegate>
@optional
// 返回第index位置cell的高度
-(CGFloat)MyWaterFlowView:(MyWaterFlowView *)mywaterflowview HeightAtIndex:(NSUInteger)index;
// 选中在index位置的cell
-(void)MyWaterFlowView:(MyWaterFlowView *)mywaterflowview DidSelectAtIndex:(NSUInteger)index;
//返回间隙
-(CGFloat)MyWaterFlowView:(MyWaterFlowView *)mywaterflowview MarginType:(MyWaterFlowViewMarginType)type;
@end
@interface MyWaterFlowView : UIScrollView
/** 数据源*/
@property(nonatomic,weak)id<MyWaterFlowViewDataSource>MyDataSource;
/** 代理方法*/
@property(nonatomic,weak)id<MyWaterFlowViewDelegate>MyDelegate;
/** 刷新数据(只要调用这个方法,会重新向数据源和代理发送请求)*/
-(void)ReloadData;
/** 根据标识去缓存池查可重复利用的cell*/
- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier;
/** cell的宽度*/
-(CGFloat)cellWidth;
@end
*************************************************************************************************************************************
************************************************************************************************************************************
*************************************************************************************************************************************
//
// MyWaterFlowView.m
// 瀑布流
//
// Created by Jose on 15-7-11.
// Copyright (c) 2015年 Jose. All rights reserved.
//
#import "MyWaterFlowView.h"
#import "MyWaterFlowViewCell.h"
#define CellHeight 70
#define CellColums 3
#define CellMargin 8
@interface MyWaterFlowView()
/** 存放cell的frame的数组*/
@property(nonatomic,strong)NSMutableArray *CellFrames;
/** 存放正在展示的cell*/
@property(nonatomic,strong)NSMutableDictionary *displayingCells;
/** 缓存池用set存放离开屏幕的cell*/
@property(nonatomic,strong)NSMutableSet *reusableCells;
@end
@implementation MyWaterFlowView
#pragma mark - 初始化
-(NSMutableArray *)CellFrames{
if (_CellFrames==nil) {
self.CellFrames=[NSMutableArray array];
}
return _CellFrames;
}
-(NSMutableDictionary *)displayingCells{
if (_displayingCells==nil) {
self.displayingCells=[NSMutableDictionary dictionary];
}
return _displayingCells;
}
-(NSMutableSet *)reusableCells{
if (_reusableCells==nil) {
self.reusableCells=[NSMutableSet set];
}
return _reusableCells;
}
-(id)initWithFrame:(CGRect)frame{
self=[super initWithFrame:frame];
if (self) {
}
return self;
}
//对于内存控制很重要
-(void)willMoveToSuperview:(UIView *)newSuperview{
[self ReloadData];
}
/**
* 公共接口
*/
-(void)ReloadData{
//移除正在显示的cell
[self.displayingCells.allValues makeObjectsPerformSelector:@selector(removeFromSuperview)];
//清空之前的所有数据
[self.displayingCells removeAllObjects];
[self.CellFrames removeAllObjects];
[self.reusableCells removeAllObjects];
//获取cell的总数
int numberofcells=[self.MyDataSource NumberOfCellInWaterFlowView:self];
//获取总列数
int numberofcolums=[self NumberOfColumns];
//获取间距
CGFloat top=[self MarginForType:MyWaterFlowViewMarginTypeTop];
CGFloat bottom=[self MarginForType:MyWaterFlowViewMarginTypeBottom];
CGFloat left=[self MarginForType:MyWaterFlowViewMarginTypeLeft];
//CGFloat right=[self MarginForType:MyWaterFlowViewMarginTypeRight];
CGFloat column=[self MarginForType:MyWaterFlowViewMarginTypeColumn];
CGFloat row=[self MarginForType:MyWaterFlowViewMarginTypeRow];
//4.获取宽度
//CGFloat cellwidth=(self.width-left-right-(numberofcolums-1)*column)/numberofcolums;
CGFloat cellwidth=[self cellWidth];
//c语言数组用来存放每一列最大的y值
CGFloat MaxYOfColumns[numberofcolums];
for (int i=0; i<numberofcolums; i++) {
MaxYOfColumns[i]=0.0;
}
//计算所有cell的frame
for (int i=0; i<numberofcells;i++) {
//cell所处最短的那列
NSUInteger CellColumn=0;
//cell所处最短那列的最大y值
CGFloat MaxYOfCellColumn=MaxYOfColumns[CellColumn];
//求出最短的那一列
for (int j=1; j<numberofcolums; j++) {
if (MaxYOfColumns[j]<MaxYOfCellColumn) {
CellColumn=j;
MaxYOfCellColumn=MaxYOfColumns[j];
}
}
//询问代理i位置的高度
CGFloat cellheight=[self HeightAtIndex:i];
//cell的位置
CGFloat cellx=left+CellColumn*(cellwidth+column);
CGFloat celly=0;
//判断是否是首行
if (MaxYOfCellColumn==0.0) {
celly=top;
}
else{
celly=MaxYOfCellColumn+row;
}
//添加到frame数组中
CGRect cellframe=CGRectMake(cellx, celly, cellwidth, cellheight);
[self.CellFrames addObject:[NSValue valueWithCGRect:cellframe]];
//更新最短那一列的y值
MaxYOfColumns[CellColumn]=CGRectGetMaxY(cellframe);
//显示cell
/***
MyWaterFlowViewCell *cell=[self.MyDataSource WaterFlowViewCell:self CellAtIndex:i];
cell.frame=cellframe;
[self addSubview:cell];
**/
}
//设置contentsize
CGFloat contentheight=MaxYOfColumns[0];
for (int j=1; j<numberofcolums; j++) {
if (MaxYOfColumns[j]>contentheight) {
contentheight=MaxYOfColumns[j];
}
}
contentheight+=bottom;
self.contentSize=CGSizeMake(0,contentheight);
}
-(void)layoutSubviews{
[super layoutSubviews];
//向数据源索要对应位置的cell
NSUInteger numberOfCells=self.CellFrames.count;
for (int i=0; i<numberOfCells; i++) {
//取出i对应位置的frame
CGRect cellframe=[self.CellFrames[i]CGRectValue];
//优先从字典中取出i位置的cell
MyWaterFlowViewCell *cell=self.displayingCells[@(i)];
if ([self isInScreen:cellframe]) {
if (cell==nil) {
cell=[self.MyDataSource WaterFlowViewCell:self CellAtIndex:i];
cell.frame=cellframe;
[self addSubview:cell];
//存放到字典中
self.displayingCells[@(i)]=cell;
}
}
else{
if (cell) {
//从scrollview中移除cell
[cell removeFromSuperview];
//从字典中移除cell
[self.displayingCells removeObjectForKey:@(i)];
//将移除的cell存放到缓存池中
[self.reusableCells addObject:cell];
}
}
}
}
//返回cell的宽度
-(CGFloat)cellWidth{
//1.获取总列数
int numberofcolums=[self NumberOfColumns];
CGFloat left=[self MarginForType:MyWaterFlowViewMarginTypeLeft];
CGFloat right=[self MarginForType:MyWaterFlowViewMarginTypeRight];
CGFloat column=[self MarginForType:MyWaterFlowViewMarginTypeColumn];
return (self.bounds.size.width-left-right-(numberofcolums-1)*column)/numberofcolums;
}
//从缓存池中取出出可以重复利用的cell
-(id)dequeueReusableCellWithIdentifier:(NSString *)identifier{
__block MyWaterFlowViewCell *reusableCell=nil;
[self.reusableCells enumerateObjectsUsingBlock:^(MyWaterFlowViewCell *cell,BOOL *stop){
if ([cell.identifier isEqualToString:identifier]) {
reusableCell=cell;
*stop=YES;
}
}];
if (reusableCell) {
// 从缓存池移除
[self.reusableCells removeObject:reusableCell];
}
return reusableCell;
}
/**
* 私有方法
*/
//判断一个frame有没有显示在屏幕上
-(BOOL)isInScreen:(CGRect)frame{
return (CGRectGetMaxY(frame)>self.contentOffset.y)&&(CGRectGetMinY(frame)<self.contentOffset.y+self.bounds.size.height);
}
//获取index位置对应cell的高度
-(CGFloat)HeightAtIndex:(NSUInteger)index{
if ([self.MyDelegate respondsToSelector:@selector(MyWaterFlowView:HeightAtIndex:)]) {
return [self.MyDelegate MyWaterFlowView:self HeightAtIndex:index];
}
else{
return CellHeight;
}
}
//事件处理
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
if (![self.MyDelegate respondsToSelector:@selector(MyWaterFlowView:DidSelectAtIndex:)])return;
UITouch *touch=[touches anyObject];
CGPoint point=[touch locationInView:self];
__block NSNumber *selectIndex=nil;
[self.displayingCells enumerateKeysAndObjectsUsingBlock:^(id key,MyWaterFlowViewCell *cell,BOOL *stop){
if (CGRectContainsPoint(cell.frame, point)) {
selectIndex=key;
*stop=YES;
}
}];
if (selectIndex) {
[self.MyDelegate MyWaterFlowView:self DidSelectAtIndex:selectIndex.unsignedIntegerValue];
}
}
//获取列数
-(NSUInteger)NumberOfColumns{
if ([self.MyDataSource respondsToSelector:@selector(NumberOfColumsInWaterFlowView:)]) {
return [self.MyDataSource NumberOfColumsInWaterFlowView:self];
}
else{
return CellColums;
}
}
//获取间距
-(CGFloat)MarginForType:(MyWaterFlowViewMarginType)type{
if ([self.MyDelegate respondsToSelector:@selector(MyWaterFlowView:MarginType:)]) {
return [self.MyDelegate MyWaterFlowView:self MarginType:type];
}
else{
return CellMargin;
}
}
@end