使用scrollView简单实现瀑布流
代码实现
waterFlowView.h--------------------------------------
#import <UIKit/UIKit.h>
typedef enum {
waterFiowViewMarginTypeTop,
waterFiowViewMarginTypeBottom,
waterFiowViewMarginTypeLeft,
waterFiowViewMarginTypeRight,
waterFiowViewMarginTypeColumn,//每一列
waterFiowViewMarginTypeRow, //每一行
}waterFiowViewMarginType;
@class waterFlowviewCell,waterFiowView;
//数据源方法
@protocol WaterFlowViewDataSource <NSObject>
//必须实现的方法
@required
//一共有多少个数据
- (NSUInteger)numberOfCellsInWaterFlowView:(waterFiowView *)waterFlowView;
//返回index位置对应的cell
- (waterFlowviewCell *)waterFlowView:(waterFiowView *)waterFlowView cellAtIndex:(NSUInteger)index;
@optional
//一共有多少列
- (NSUInteger)numberOfColumnsInWaterFlowView:(waterFiowView *)waterFlowView;
@end
//代理方法
@protocol WaterFlowViewDelegate <UIScrollViewDelegate>
@optional
//第index位置cell对应的高度
- (CGFloat)waterFlowView:(waterFiowView *)waterFiowView heightAtIndex:(NSUInteger)index;
//选中第index位置的cell
- (void)waterFiowView:(waterFiowView *)waterFiowView didSelectAtIndex:(NSUInteger)index;
//返回间距
- (CGFloat)waterFiowView:(waterFiowView *)waterFiowView marginForType:(waterFiowViewMarginType)type;
@end
@interface waterFiowView :UIScrollView
@property(nonatomic,weak)id<WaterFlowViewDataSource>datasource;
@property(nonatomic,weak)id<WaterFlowViewDelegate>delegate;
- (CGFloat)cellWidth;
- (void)reloadData;
- (id)dequeuereusableCellWithIdentifier:(NSString *)indentifier;
@end
#import "waterFiowView.h"
#import "waterFlowviewCell.h"
#define waterFlowViewDefaultNumberOfClunms 3
#define waterFiowViewDefaultCellH 100
#define waterFiowViewDefaultMargin 10
@interface waterFiowView()
@property(nonatomic,strong)NSMutableArray *cellFrames;
@property(nonatomic,strong)NSMutableDictionary *displayingcells;
@property(nonatomic,strong)NSMutableSet *reusableCells;
@end
//1,计算每个cell的frame
- (void)reloadData{
_displayingcells = [NSMutableDictionarydictionary];
//cell的总数是多少
int numberOfCells = (int)[self.datasourcenumberOfCellsInWaterFlowView:self];
//cell的列数
int numberOfColumns = (int)[selfnumberOfColumns];
//间距
CGFloat leftM = [selfmarginForType:waterFiowViewMarginTypeLeft];
CGFloat rightM = [selfmarginForType:waterFiowViewMarginTypeRight];
CGFloat ColumnM = [selfmarginForType:waterFiowViewMarginTypeColumn];
CGFloat topM = [selfmarginForType:waterFiowViewMarginTypeTop];
CGFloat rowM = [selfmarginForType:waterFiowViewMarginTypeRow];
CGFloat bottomM = [selfmarginForType:waterFiowViewMarginTypeBottom];
//1cell的宽度
//cell的宽度=(整个view的宽度-左边的间距-右边的间距-(列数-1)x每列之间的间距)/总列数
CGFloat cellW = (self.frame.size.width - leftM-rightM-(numberOfColumns-1)*ColumnM)/numberOfColumns;
//用一个c语言的数组来存放所有列的最大y值
CGFloat maxYOfColumns[numberOfColumns];
for (int i =0; i <numberOfColumns; i++) {
//初始化数组的数值全部为0
maxYOfColumns[i] =0;
}
//计算每个cell的frame
for (int i =0; i < numberOfCells ; i++) {
//2cell的高度
//i 位置的高度
CGFloat cellH = [selfheightAtIndex:i];
//cell处在第几列(最短的一列)
NSUInteger cellAtColumn = 0;
//cell所处那列的最大y值(当前最短的那一列的最大的y值)
//默认设置最短的一列为第一列
CGFloat maxYOfCellAtColumn = maxYOfColumns[cellAtColumn];
//求出最短的那一列
for (int j =0 ; j < numberOfColumns; j++) {
if (maxYOfColumns[j]<maxYOfCellAtColumn) {
cellAtColumn = j;
maxYOfCellAtColumn = maxYOfColumns[j];
}
}
//3cell的位置
//cell的x=左边的间距+列号*(cell的宽度+每列之间的间距)
CGFloat cellX = leftM + cellAtColumn * (cellW +ColumnM);
//cell的y,先设定为0
CGFloat cellY = 0;
if (maxYOfCellAtColumn == 0.0) {//首行
cellY = topM;
}else{
cellY = maxYOfCellAtColumn + rowM;
}
//设置cell的frame并添加到数组中去
CGRect cellFrame = CGRectMake(cellX, cellY, cellW, cellH);
[self.cellFramesaddObject:[NSValuevalueWithCGRect:cellFrame]];
//更新最短那一列的最大的y值
maxYOfColumns[cellAtColumn] =CGRectGetMaxY(cellFrame);
// waterFlowviewCell *cell = [self.datasource waterFlowView:self cellAtIndex:i];
// cell.frame = cellFrame;
// [self addSubview:cell];
}
//设置contentSize
CGFloat contentH = maxYOfColumns[0];
for (int i =0; i <numberOfColumns; i++) {
if (maxYOfColumns[i] > contentH) {
contentH = maxYOfColumns[i];
}
}
contentH +=bottomM;
self.contentSize =CGSizeMake(0, contentH);
}
- (void)layoutSubviews{
[superlayoutSubviews];
//向数据源索要对应位置的cell
NSUInteger numberOfCells = self.cellFrames.count;
for (int i =0; i < numberOfCells; i++) {
//取出i位置的frame
CGRect cellFrame = [self.cellFrames[i]CGRectValue];
//--------------------------------------------
//优先从字典中出去i位置的cell
waterFlowviewCell *cell =self.displayingcells[@(i)];
//----------------------------------------------
if ([self isInScreen:cellFrame]) {//在屏幕上
// waterFlowviewCell *cell = self.displayingcells[@(i)];
if (cell == nil) {
cell = [self.datasourcewaterFlowView:selfcellAtIndex:i];
cell.frame = cellFrame;
//[self addSubview:cell];
//存放在字典中
self.displayingcells[@(i)] = cell;
[selfaddSubview:cell];
}
}else{
if (cell) {
[cellremoveFromSuperview];
[self.displayingcellsremoveObjectForKey:@(i)];
//存放进缓存池
[self.reusableCellsaddObject:cell];
}
}
}
NSLog(@"-----%ld",self.subviews.count);
}
- (id)dequeuereusableCellWithIdentifier:(NSString *)indentifier{
__block waterFlowviewCell *reusableCell =nil;
[self.reusableCellsenumerateObjectsUsingBlock:^(waterFlowviewCell *cell,BOOL *stop) {
if([cell.identifierisEqualToString:indentifier]){
reusableCell = cell;
*stop =YES;
}
}];
if (reusableCell) {
[self.reusableCellsremoveObject:reusableCell];
}
return reusableCell;
}
- (BOOL)isInScreen:(CGRect)frame{
return (CGRectGetMaxY(frame)>self.contentOffset.y) && (CGRectGetMinY(frame)<self.contentOffset.y+self.frame.size.height);
}
-------------------
- (CGFloat)marginForType:(waterFiowViewMarginType)type{
if ([self.delegaterespondsToSelector:@selector(waterFiowView:marginForType:)]) {
return [self.delegatewaterFiowView:selfmarginForType:type];
}else{
returnwaterFiowViewDefaultMargin;
}
}
- (NSUInteger)numberOfColumns{
if ([self.datasourcerespondsToSelector:@selector(numberOfColumnsInWaterFlowView:)]) {
return [self.datasourcenumberOfColumnsInWaterFlowView:self];
}else{
returnwaterFlowViewDefaultNumberOfClunms;
}
}
- (CGFloat)heightAtIndex:(NSUInteger)index{
if ([self.delegaterespondsToSelector:@selector(waterFlowView:heightAtIndex:)]) {
return [self.delegatewaterFlowView:selfheightAtIndex:index];
}else{
returnwaterFiowViewDefaultCellH;
}
}
实现waterFlowView的DataSource和Delegate方法
- (waterFlowviewCell *)waterFlowView:(waterFiowView *)waterFlowView cellAtIndex:(NSUInteger)index{
static NSString *inde =@"cell";
waterFlowviewCell *cell = [waterFlowView dequeuereusableCellWithIdentifier:inde];
if (cell == nil) {
cell = [[waterFlowviewCellalloc] init];
cell.identifier = inde;
//cell.backgroundColor = [UIColor purpleColor];
// [cell addSubview:[UIButton buttonWithType:UIButtonTypeContactAdd]];
cell.backgroundColor = [UIColorcolorWithRed:arc4random()%10*.1green:arc4random()%10*.1 blue:arc4random()%10*.1 alpha:.1];
UILabel *label = [[UILabelalloc] initWithFrame:CGRectMake(5,5, 25, 25)];
label.tag =120;
[celladdSubview:label];
}
UILabel *label = (UILabel *)[cellviewWithTag:120];
label.text = [NSStringstringWithFormat:@"%ld",index];
// NSLog(@"%ld--%p",index,cell);
return cell;
}
- (CGFloat)waterFlowView:(waterFiowView *)waterFiowView heightAtIndex:(NSUInteger)index{
switch (index%3) {
case 0:
return 90;
case 1:
return 110;
case 2:
return 80;
default:
return 120;
}
}
- (CGFloat)waterFiowView:(waterFiowView *)waterFiowView marginForType:(waterFiowViewMarginType)type{
switch (type) {
casewaterFiowViewMarginTypeTop:
casewaterFiowViewMarginTypeBottom:
casewaterFiowViewMarginTypeLeft:
casewaterFiowViewMarginTypeRight:
return 10;
casewaterFiowViewMarginTypeColumn:
casewaterFiowViewMarginTypeRow:
return 5;
}
}
- (void)waterFiowView:(waterFiowView *)waterFiowView didSelectAtIndex:(NSUInteger)index{
NSLog(@"点击了%ld的cell",index);
}
运行效果