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个滚动条(水平方向上的滚动条被隐藏了,但是仍然存在)
优化思路:放入到缓存池。


转载:http://www.cnblogs.com/wendingding/p/3876039.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ava实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),可运行高分资源 Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。下面详细介绍C语言的基本概念和语法。 1. 变量和数据类型 在C语言中,变量用于存储数据,数据类型用于定义变量的类型和范围。C语言支持多种数据类型,包括基本数据类型(如int、float、char等)和复合数据类型(如结构体、联合等)。 2. 运算符 C语言中常用的运算符包括算术运算符(如+、、、/等)、关系运算符(如==、!=、、=、<、<=等)、逻辑运算符(如&&、||、!等)。此外,还有位运算符(如&、|、^等)和指针运算符(如、等)。 3. 控制结构 C语言中常用的控制结构包括if语句、循环语句(如for、while等)和switch语句。通过这些控制结构,可以实现程序的分支、循环和多路选择等功能。 4. 函数 函数是C语言中用于封装代码的单元,可以实现代码的复用和模块化。C语言中定义函数使用关键字“void”或返回值类型(如int、float等),并通过“{”和“}”括起来的代码块来实现函数的功能。 5. 指针 指针是C语言中用于存储变量地址的变量。通过指针,可以实现对内存的间接访问和修改。C语言中定义指针使用星号()符号,指向数组、字符串和结构体等数据结构时,还需要注意数组名和字符串常量的特殊性质。 6. 数组和字符串 数组是C语言中用于存储同类型数据的结构,可以通过索引访问和修改数组中的元素。字符串是C语言中用于存储文本数据的特殊类型,通常以字符串常量的形式出现,用双引号("...")括起来,末尾自动添加'\0'字符。 7. 结构体和联合 结构体和联合是C语言中用于存储不同类型数据的复合数据类型。结构体由多个成员组成,每个成员可以是不同的数据类型;联合由多个变量组成,它们共用同一块内存空间。通过结构体和联合,可以实现数据的封装和抽象。 8. 文件操作 C语言中通过文件操作函数(如fopen、fclose、fread、fwrite等)实现对文件的读写操作。文件操作函数通常返回文件指针,用于表示打开的文件。通过文件指针,可以进行文件的定位、读写等操作。 总之,C语言是一种功能强大、灵活高效的编程语言,广泛应用于各种领域。掌握C语言的基本语法和数据结构,可以为编程学习和实践打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值