iOS开发UI篇—自定义瀑布流控件(基本实现)

iOS开发UI篇—自定义瀑布流控件(基本实现)

一、基本实现

说明:在View加载的时候,刷新数据。

1.实现代码

YYViewController.m文件

 1 //
 2 //  YYViewController.m
 3 //  06-瀑布流
 4 //
 5 //  Created by apple on 14-7-28.
 6 //  Copyright (c) 2014年 wendingding. All rights reserved.
 7 //
 8
 9 #import "YYViewController.h"
10 #import "YYWaterflowView.h"
11 #import "YYWaterflowViewCell.h"
12
13 @interface YYViewController ()<YYWaterflowViewDelegate,YYWaterflowViewDataSource>
14
15 @end
16
17 @implementation YYViewController
18
19 - (void)viewDidLoad
20 {
21     [super viewDidLoad];
22     YYWaterflowView *waterflow=[[YYWaterflowView alloc]init];
23     waterflow.frame=self.view.bounds;
24     waterflow.delegate=self;
25     waterflow.dadaSource=self;
26     [self.view addSubview:waterflow];
27
28     //刷新数据
29     [waterflow reloadData];
30 }
31
32 #pragma mark-数据源方法
33 -(NSUInteger)numberOfCellsInWaterflowView:(YYWaterflowView *)waterflowView
34 {
35     return 100;
36 }
37 -(NSUInteger)numberOfColumnsInWaterflowView:(YYWaterflowView *)waterflowView
38 {
39     return 3;
40 }
41 -(YYWaterflowViewCell *)waterflowView:(YYWaterflowView *)waterflowView cellAtIndex:(NSUInteger)index
42 {
43     YYWaterflowViewCell *cell=[[YYWaterflowViewCell alloc]init];
44     //给cell设置一个随机色
45     cell.backgroundColor=YYRandomColor;
46     return cell;
47 }
48
49
50 #pragma mark-代理方法
51 -(CGFloat)waterflowView:(YYWaterflowView *)waterflowView heightAtIndex:(NSUInteger)index
52 {
53     switch (index%3) {
54         case 0:return 90;
55         case 1:return 110;
56         case 2:return 80;
57         default:return 120;
58     }
59 }
60 -(CGFloat)waterflowView:(YYWaterflowView *)waterflowView marginForType:(YYWaterflowViewMarginType)type
61 {
62     switch (type) {
63         case YYWaterflowViewMarginTypeTop:
64         case YYWaterflowViewMarginTypeBottom:
65         case YYWaterflowViewMarginTypeLeft:
66         case YYWaterflowViewMarginTypeRight:
67             return 10;
68         case YYWaterflowViewMarginTypeColumn:
69         case YYWaterflowViewMarginTypeRow:
70             return 5;
71     }
72 }
73 -(void)waterflowView:(YYWaterflowView *)waterflowView didSelectAtIndex:(NSUInteger)index
74 {
75     NSLog(@"点击了%d的cell",index);
76 }
77 @end

YYWaterflowView.h文件

 1 //
 2 //  YYWaterflowView.h
 3 //  06-瀑布流
 4 //
 5 //  Created by apple on 14-7-29.
 6 //  Copyright (c) 2014年 wendingding. All rights reserved.
 7 //
 8
 9 #import <UIKit/UIKit.h>
10
11 //使用瀑布流形式展示内容的控件
12 typedef enum {
13     YYWaterflowViewMarginTypeTop,
14     YYWaterflowViewMarginTypeBottom,
15     YYWaterflowViewMarginTypeLeft,
16     YYWaterflowViewMarginTypeRight,
17     YYWaterflowViewMarginTypeColumn,//每一列
18     YYWaterflowViewMarginTypeRow,//每一行
19
20 }YYWaterflowViewMarginType;
21
22 @class YYWaterflowViewCell,YYWaterflowView;
23
24 /**
25  *  1.数据源方法
26  */
27 @protocol YYWaterflowViewDataSource <NSObject>
28 //要求强制实现
29 @required
30 /**
31  * (1)一共有多少个数据
32  */
33 -(NSUInteger)numberOfCellsInWaterflowView:(YYWaterflowView *)waterflowView;
34 /**
35  *  (2)返回index位置对应的cell
36  */
37 -(YYWaterflowViewCell *)waterflowView:(YYWaterflowView *)waterflowView cellAtIndex:(NSUInteger)index;
38
39 //不要求强制实现
40 @optional
41 /**
42  *  (3)一共有多少列
43  */
44 -(NSUInteger)numberOfColumnsInWaterflowView:(YYWaterflowView *)waterflowView;
45
46 @end
47
48
49 /**
50  *  2.代理方法
51  */
52 @protocol YYWaterflowViewDelegate <UIScrollViewDelegate>
53 //不要求强制实现
54 @optional
55 /**
56  *  (1)第index位置cell对应的高度
57  */
58 -(CGFloat)waterflowView:(YYWaterflowView *)waterflowView heightAtIndex:(NSUInteger)index;
59 /**
60  *  (2)选中第index位置的cell
61  */
62 -(void)waterflowView:(YYWaterflowView *)waterflowView didSelectAtIndex:(NSUInteger)index;
63 /**
64  *  (3)返回间距
65  */
66 -(CGFloat)waterflowView:(YYWaterflowView *)waterflowView marginForType:(YYWaterflowViewMarginType)type;
67 @end
68
69
70 /**
71  *  3.瀑布流控件
72  */
73 @interface YYWaterflowView : UIScrollView
74 /**
75  *  (1)数据源
76  */
77 @property(nonatomic,weak)id<YYWaterflowViewDataSource> dadaSource;
78 /**
79  *  (2)代理
80  */
81 @property(nonatomic,weak)id<YYWaterflowViewDelegate> delegate;
82
83 /**
84  *  刷新数据
85  */
86 -(void)reloadData;
87 @end

瀑布流的内部实现(计算每个cell的frame)

YYWaterflowView.m文件的代码

  1 //
  2 //  YYWaterflowView.m
  3 //  06-瀑布流
  4 //
  5 //  Created by apple on 14-7-29.
  6 //  Copyright (c) 2014年 wendingding. All rights reserved.
  7 //
  8
  9 #import "YYWaterflowView.h"
 10 #import "YYWaterflowViewCell.h"
 11 #define YYWaterflowViewDefaultNumberOfClunms  3
 12 #define YYWaterflowViewDefaultCellH  100
 13 #define YYWaterflowViewDefaultMargin 10
 14
 15 @interface YYWaterflowView()
 16 @property(nonatomic,strong)NSMutableArray *cellFrames;
 17 @end
 18
 19 @implementation YYWaterflowView
 20
 21 #pragma mark-懒加载
 22 -(NSMutableArray *)cellFrames
 23 {
 24     if (_cellFrames==nil) {
 25         _cellFrames=[NSMutableArray array];
 26     }
 27     return _cellFrames;
 28 }
 29
 30 - (id)initWithFrame:(CGRect)frame
 31 {
 32     self = [super initWithFrame:frame];
 33     if (self) {
 34     }
 35     return self;
 36 }
 37
 38 /**
 39  *  刷新数据
 40  *  1.计算每个cell的frame
 41  */
 42 -(void)reloadData
 43 {
 44     //cell的总数是多少
 45     int numberOfCells=[self.dadaSource numberOfCellsInWaterflowView:self];
 46
 47     //cell的列数
 48     int numberOfColumns=[self numberOfColumns];
 49
 50     //间距
 51     CGFloat leftM=[self marginForType:YYWaterflowViewMarginTypeLeft];
 52     CGFloat rightM=[self marginForType:YYWaterflowViewMarginTypeRight];
 53     CGFloat columnM=[self marginForType:YYWaterflowViewMarginTypeColumn];
 54     CGFloat topM=[self marginForType:YYWaterflowViewMarginTypeTop];
 55     CGFloat rowM=[self marginForType:YYWaterflowViewMarginTypeRow];
 56     CGFloat bottomM=[self marginForType:YYWaterflowViewMarginTypeBottom];
 57
 58     //(1)cell的宽度
 59     //cell的宽度=(整个view的宽度-左边的间距-右边的间距-(列数-1)X每列之间的间距)/总列数
 60     CGFloat cellW=(self.frame.size.width-leftM-rightM-(numberOfColumns-1)*columnM)/numberOfColumns;
 61
 62
 63
 64     //用一个C语言的数组来存放所有列的最大的Y值
 65     CGFloat maxYOfColumns[numberOfColumns];
 66     for (int i=0; i<numberOfColumns; i++) {
 67         //初始化数组的数值全部为0
 68         maxYOfColumns[i]=0.0;
 69     }
 70
 71
 72     //计算每个cell的fram
 73     for (int i=0; i<numberOfCells; i++) {
 74
 75         //(2)cell的高度
 76         //询问代理i位置的高度
 77         CGFloat cellH=[self heightAtIndex:i];
 78
 79         //cell处在第几列(最短的一列)
 80         NSUInteger cellAtColumn=0;
 81
 82         //cell所处那列的最大的Y值(当前最短的那一列的最大的Y值)
 83         //默认设置最短的一列为第一列(优化性能)
 84         CGFloat maxYOfCellAtColumn=maxYOfColumns[cellAtColumn];
 85
 86         //求出最短的那一列
 87         for (int j=0; j<numberOfColumns; j++) {
 88             if (maxYOfColumns[j]<maxYOfCellAtColumn) {
 89                 cellAtColumn=j;
 90                 maxYOfCellAtColumn=maxYOfColumns[j];
 91             }
 92         }
 93
 94         //(3)cell的位置(X,Y)
 95         //cell的X=左边的间距+列号*(cell的宽度+每列之间的间距)
 96         CGFloat cellX=leftM+cellAtColumn*(cellW +columnM);
 97         //cell的Y,先设定为0
 98         CGFloat cellY=0;
 99         if (maxYOfCellAtColumn==0.0) {//首行
100             cellY=topM;
101         }else
102         {
103             cellY=maxYOfCellAtColumn+rowM;
104         }
105
106         //(4)设置cell的frame并添加到数组中
107         CGRect cellFrame=CGRectMake(cellX, cellY, cellW, cellH);
108         [self.cellFrames addObject:[NSValue valueWithCGRect:cellFrame]];
109
110         //更新最短那一列的最大的Y值
111         maxYOfColumns[cellAtColumn]=CGRectGetMaxY(cellFrame);
112
113         //显示cell
114         YYWaterflowViewCell *cell=[self.dadaSource waterflowView:self cellAtIndex:i];
115         cell.frame=cellFrame;
116         [self addSubview:cell];
117     }
118
119     //设置contentSize
120     CGFloat contentH=maxYOfColumns[0];
121     for (int i=1; i<numberOfColumns; i++) {
122         if (maxYOfColumns[i]>contentH) {
123             contentH=maxYOfColumns[i];
124         }
125     }
126     contentH += bottomM;
127     self.contentSize=CGSizeMake(0, contentH);
128 }
129
130 #pragma mark-私有方法
131 -(CGFloat)marginForType:(YYWaterflowViewMarginType)type
132 {
133     if ([self.delegate respondsToSelector:@selector(waterflowView:marginForType:)]) {
134        return  [self.delegate waterflowView:self marginForType:type];
135     }else
136     {
137         return YYWaterflowViewDefaultMargin;
138     }
139 }
140
141 -(NSUInteger)numberOfColumns
142 {
143     if ([self.dadaSource respondsToSelector:@selector(numberOfColumnsInWaterflowView:)]) {
144         return [self.dadaSource numberOfColumnsInWaterflowView:self];
145     }else
146     {
147         return  YYWaterflowViewDefaultNumberOfClunms;
148     }
149 }
150
151 -(CGFloat)heightAtIndex:(NSUInteger)index
152 {
153     if ([self.delegate respondsToSelector:@selector(waterflowView:heightAtIndex:)]) {
154         return [self.delegate waterflowView:self heightAtIndex:index];
155     }else
156     {
157         return YYWaterflowViewDefaultCellH;
158     }
159 }
160 @end

实现的瀑布流效果:

     

2.简单说明

说明:

(1)瀑布流每一个的宽度是一样的,都是高度不一样

(2)补齐算法,哪里比较短就补哪里,不是简单的从左到右排(两列之间的差距越来越大)。

这就要求我们时刻知道每一列最大的Y值是多少,以比较哪里“最短”。

可以考虑使用一个C语言的数组来存放所有列的最大Y值

注意数组的初始化操作。

提示:瀑布流的最后一行一般都是参差不齐的。

可扩展性:

简单的修改cell的列数,即可修改布局。

(1)设置瀑布流为2列。

(2)设置瀑布流的列数为4列

(3)如果不设置列数,那么显示的列数默认为3列。

(4)如果不设置高度,那么显示的cell的高度为默认的高度,都是一样的。

  

(5)cell的上下左右,行和列之间的间距也可以进行调整,这里不做演示。

(6)在cell中可以添加自定义的控件,如Button、imageView等,此时可以向使用UITableView和UITableViewcell一样来使用YYWaterflowView和YYWaterflowViewCell。

3.存在的问题

  上面的代码对cell的处理存在很大的性能问题,如果程序中又2000个cell,那么这里就创建了两千个cell,性能很差。

  可以通过在layoutSubviews方法中打印查看。

说明:之所以为2002,是因为创建了2000个cell+2个滚动条(水平方向上的滚动条被隐藏了,但是仍然存在)

优化思路:放入到缓存池。

iOS开发UI篇—自定义瀑布流控件(基本实现),布布扣,bubuko.com

时间: 2024-12-26 09:18:32

iOS开发UI篇—自定义瀑布流控件(基本实现)的相关文章

iOS开发UI篇—自定义瀑布流控件(蘑菇街数据刷新操作)

iOS开发UI篇—自定义瀑布流控件(蘑菇街数据刷新操作) 一.简单说明 使用数据刷新框架: 该框架提供了两种刷新的方法,一个是使用block回调(存在循环引用问题,_ _weak),一个是使用调用. 问题:在进行下拉刷新之前,应该要清空之前的所有数据(在刷新数据这个方法中). 移除正在显示的cell: (1)把字典中的所有的值,都从屏幕上移除 (2)清除字典中的所有元素 (3)清除cell的frame,每个位置的cell的frame都要重新计算 (4)清除可复用的缓存池. 该部分的代码如下: 1

iOS开发UI篇—自定义瀑布流控件(蘑菇街实现)

iOS开发UI篇—自定义瀑布流控件(蘑菇街瀑布流) 一.简单说明 关于瀑布流 1.是使用UIScrollView实现的 2.刷新数据(reloadData)方法里面做哪些事情 3.layoutSubviews方法里面做哪些事情 4.模仿UItableView进行设计 完善: 瀑布流控件第一次显示到屏幕上的时候自动的向数据源索要数据,而不需要手动调用.这需要监听View的显示,View的显示有一个方法,叫做willMoveToSuperview:在该方法中直接刷新一次数据即可. 二.把自定义的瀑布

iOS开发UI篇—自定义瀑布流控件(接口设计)

iOS开发UI篇—自定义瀑布流控件(接口设计) 一.简单说明 1.关于瀑布流 电商应用要展示商品信息通常是通过瀑布流的方式,因为每个商品的展示图片,长度和商都都不太一样. 如果不用瀑布流的话,展示这样的格子数据,还有一种办法是使用九宫格. 但利用九宫格有一个缺点,那就是每个格子的宽高是一样的,如果一定要使用九宫格来展示,那么展示的商品图片可能会变形. 为了保证商品图片能够按照原来的宽高比进行展示,一般采用的是瀑布流的方式. 2.瀑布流的特点: 由很多的格子组成,但是每个格子的宽度和高速都是不确定

iOS开发UI篇—自定义瀑布流控件(cell的循环利用)

iOS开发UI篇—自定义瀑布流控件(cell的循环利用) 一.简单说明 当滚动的时候,向数据源要cell. 当UIScrollView滚动的时候会调用layoutSubviews在tableView中也是一样的,因此,可以用这个方法来监听scrollView的滚动,可以在在这个地方向数据源索要对应位置的cell(frame在屏幕上的cell). 示例: 当scrollView在屏幕上滚动的时候,离开屏幕的cell应该放到缓存池中去,询问即将(已经)进入到屏幕的cell,对于还没有进入到屏幕的ce

iOS开发UI篇—DatePicker和UIToolBar控件简单介绍

iOS开发UI篇—DatePicker和UIToolBar控件简单介绍 一.Date Picker控件 1.简单介绍: Date Picker显示时间的控件 有默认宽高,不用设置数据源和代理 如何改成中文的? (1)查看当前系统是否为中文的,把模拟器改成是中文的 (2)属性,locale选择地区 如果默认显示不符合需求.时间有四种模式可以设置,在model中进行设置 时间可以自定义(custom). 设置最小时间和最大时间,超过就会自动回到最小时间. 最大的用途在于自定义键盘:弹出一个日期选择器

iOS开发UI篇—使用picker View控件完成一个简单的选餐应用 - 文顶顶

原文  http://www.cnblogs.com/wendingding/p/3771047.html iOS开发UI篇—使用picker View控件完成一个简单的选餐应用 一.实现效果 说明: 点击随机按钮,能够自动选取,下方数据自动刷新. 二.实现思路 1.picker view的有默认高度为162,不可修改. 2.显示数据,需要设置数据源,也有两种方式(成为数据源,遵守协议) 3.实现数据源里面的两个方法 1)返回一共有多少列 2)在这一列中一共有多少行 4.通过代理告诉它那一列的哪

iOS开发UI篇—使用picker View控件完成一个简单的选餐应用

一.实现效果 说明:点击随机按钮,能够自动选取,下方数据自动刷新. 二.实现思路 1.picker view的有默认高度为162,不可修改. 2.显示数据,需要设置数据源,也有两种方式(成为数据源,遵守协议) 3.实现数据源里面的两个方法 1)返回一共有多少列 2)在这一列中一共有多少行 4.通过代理告诉它那一列的哪一行显示哪些数据(设置其代理为控制器) 5.使用懒加载,加载所有的食物 6.完成基本数据的展示(列,行,内容) 7.自动更新选中的食物信息.(使用一个大的view,上面放6个labe

iOS—自定义瀑布流控件

一.简单说明 使用数据刷新框架: 该框架提供了两种刷新的方法,一个是使用block回调(存在循环引用问题,_ _weak),一个是使用调用. 问题:在进行下拉刷新之前,应该要清空之前的所有数据(在刷新数据这个方法中). 移除正在显示的cell: (1)把字典中的所有的值,都从屏幕上移除 (2)清除字典中的所有元素 (3)清除cell的frame,每个位置的cell的frame都要重新计算 (4)清除可复用的缓存池. 该部分的代码如下: 1 // 2 // YYWaterflowView.m 3

iOS开发UI篇—实现UItableview控件数据刷新

iOS开发UI篇—实现UItableview控件数据刷新 一.项目文件结构和plist文件 二.实现效果 1.说明:这是一个英雄展示界面,点击选中行,可以修改改行英雄的名称(完成数据刷新的操作). 运行界面: 点击选中行: 修改数据后自动刷新: 三.代码示例 数据模型部分: YYheros.h文件 // // YYheros.h // 10-英雄展示(数据刷新) // // Created by apple on 14-5-29. // Copyright (c) 2014年 itcase. A