iOS开发UI篇—自定义瀑布流控件(cell的事件处理)

iOS开发UI篇—自定义瀑布流控件(cell的事件处理)

一、关于cell的复用的补充

在设置每个索引位置对应的cell的方法中,打印cell的索引和地址,已查看cell的循环利用情况

复制代码
 1 -(YYWaterflowViewCell *)waterflowView:(YYWaterflowView *)waterflowView cellAtIndex:(NSUInteger)index
 2 {
 3 //    YYWaterflowViewCell *cell=[[YYWaterflowViewCell alloc]init];
 4 
 5     static NSString *ID=@"cell";
 6     YYWaterflowViewCell *cell=[waterflowView dequeueReusableCellWithIdentifier:ID];
 7     if (cell==nil) {
 8         cell=[[YYWaterflowViewCell alloc]init];
 9         cell.identifier=ID;
10         //给cell设置一个随机色
11         cell.backgroundColor=YYRandomColor;
12 //        [cell addSubview:[UIButton buttonWithType:UIButtonTypeContactAdd]];
13     }
14     //通过取出cell中的label,重新为label的text赋值
15     
16     NSLog(@"%d---%p",index,cell);
17     return cell;
18 }
复制代码

查看:

 

二、事件处理

1.在cell创建的时候添加一个label,设置label的tag值,以便在之后能够获取到label。

代码示例:

YYViewController.m文件

复制代码
 1 //  YYViewController.m
 2 //  06-瀑布流
 3 //
 4 //  Created by apple on 14-7-28.
 5 //  Copyright (c) 2014年 wendingding. All rights reserved.
 6 //
 7 
 8 #import "YYViewController.h"
 9 #import "YYWaterflowView.h"
10 #import "YYWaterflowViewCell.h"
11 
12 @interface YYViewController ()<YYWaterflowViewDelegate,YYWaterflowViewDataSource>
13 
14 @end
15 
16 @implementation YYViewController
17 
18 - (void)viewDidLoad
19 {
20     [super viewDidLoad];
21     YYWaterflowView *waterflow=[[YYWaterflowView alloc]init];
22     waterflow.frame=self.view.bounds;
23     waterflow.delegate=self;
24     waterflow.dadaSource=self;
25     [self.view addSubview:waterflow];
26     
27     //刷新数据
28     [waterflow reloadData];
29 }
30 
31 #pragma mark-数据源方法
32 -(NSUInteger)numberOfCellsInWaterflowView:(YYWaterflowView *)waterflowView
33 {
34     return 40;
35 }
36 -(NSUInteger)numberOfColumnsInWaterflowView:(YYWaterflowView *)waterflowView
37 {
38     return 3;
39 }
40 -(YYWaterflowViewCell *)waterflowView:(YYWaterflowView *)waterflowView cellAtIndex:(NSUInteger)index
41 {
42 //    YYWaterflowViewCell *cell=[[YYWaterflowViewCell alloc]init];
43 
44     static NSString *ID=@"cell";
45     YYWaterflowViewCell *cell=[waterflowView dequeueReusableCellWithIdentifier:ID];
46     if (cell==nil) {
47         cell=[[YYWaterflowViewCell alloc]init];
48         cell.identifier=ID;
49         //给cell设置一个随机色
50         cell.backgroundColor=YYRandomColor;
51 //        [cell addSubview:[UIButton buttonWithType:UIButtonTypeContactAdd]];
52         //在cell中添加一个label,设置tag值
53         UILabel *label=[[UILabel alloc]init];
54         label.tag=10;
55         //注意:需要设置控件的frame值,否则不会显示
56         label.frame=CGRectMake(0, 0, 20, 20);
57         [cell addSubview:label];
58     }
59     //通过取出cell中的label,重新为label的text赋值
60     UILabel *label=(UILabel *)[cell viewWithTag:10];
61     label.text=[NSString stringWithFormat:@"%d",index];
62     
63     NSLog(@"%d---%p",index,cell);
64     return cell;
65 }
66 
67 
68 #pragma mark-代理方法
69 -(CGFloat)waterflowView:(YYWaterflowView *)waterflowView heightAtIndex:(NSUInteger)index
70 {
71     switch (index%3) {
72         case 0:return 90;
73         case 1:return 110;
74         case 2:return 80;
75         default:return 120;
76     }
77 }
78 -(CGFloat)waterflowView:(YYWaterflowView *)waterflowView marginForType:(YYWaterflowViewMarginType)type
79 {
80     switch (type) {
81         case YYWaterflowViewMarginTypeTop:
82         case YYWaterflowViewMarginTypeBottom:
83         case YYWaterflowViewMarginTypeLeft:
84         case YYWaterflowViewMarginTypeRight:
85             return 10;
86         case YYWaterflowViewMarginTypeColumn:
87         case YYWaterflowViewMarginTypeRow:
88             return 5;
89     }
90 }
91 -(void)waterflowView:(YYWaterflowView *)waterflowView didSelectAtIndex:(NSUInteger)index
92 {
93     NSLog(@"点击了第%d个cell",index);
94 }
95 @end
复制代码

2.在YYWaterflowView.m中,监听手指对瀑布流的触碰,获得手指在屏幕上点击的触摸点,判断该触摸点是否在cell上,在哪个cell上?

  如果点击了cell调用代理方法,那么处理对应cell的点击事件。

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 /**
 17  *  所有cell的frame数据
 18  */
 19 @property(nonatomic,strong)NSMutableArray *cellFrames;
 20 /**
 21  *  正在展示的cell
 22  */
 23 @property(nonatomic,strong)NSMutableDictionary  *displayingCells;
 24 /**
 25  *  缓存池(使用SET)
 26  */
 27 @property(nonatomic,strong)NSMutableSet *reusableCells;
 28 @end
 29 
 30 @implementation YYWaterflowView
 31 
 32 #pragma mark-懒加载
 33 -(NSMutableArray *)cellFrames
 34 {
 35     if (_cellFrames==nil) {
 36         _cellFrames=[NSMutableArray array];
 37     }
 38     return _cellFrames;
 39 }
 40 
 41 -(NSMutableDictionary *)displayingCells
 42 {
 43     if (_displayingCells==nil) {
 44         _displayingCells=[NSMutableDictionary dictionary];
 45     }
 46     return _displayingCells;
 47 }
 48 
 49 -(NSMutableSet *)reusableCells
 50 {
 51     if (_reusableCells==nil) {
 52         _reusableCells=[NSMutableSet set];
 53     }
 54     return _reusableCells;
 55 }
 56 
 57 - (id)initWithFrame:(CGRect)frame
 58 {
 59     self = [super initWithFrame:frame];
 60     if (self) {
 61     }
 62     return self;
 63 }
 64 
 65 #pragma mark-公共方法
 66 /**
 67  *  刷新数据
 68  *  1.计算每个cell的frame
 69  */
 70 -(void)reloadData
 71 {
 72     //cell的总数是多少
 73     int numberOfCells=[self.dadaSource numberOfCellsInWaterflowView:self];
 74     
 75     //cell的列数
 76     int numberOfColumns=[self numberOfColumns];
 77     
 78     //间距
 79     CGFloat leftM=[self marginForType:YYWaterflowViewMarginTypeLeft];
 80     CGFloat rightM=[self marginForType:YYWaterflowViewMarginTypeRight];
 81     CGFloat columnM=[self marginForType:YYWaterflowViewMarginTypeColumn];
 82     CGFloat topM=[self marginForType:YYWaterflowViewMarginTypeTop];
 83     CGFloat rowM=[self marginForType:YYWaterflowViewMarginTypeRow];
 84     CGFloat bottomM=[self marginForType:YYWaterflowViewMarginTypeBottom];
 85     
 86     //(1)cell的宽度
 87     //cell的宽度=(整个view的宽度-左边的间距-右边的间距-(列数-1)X每列之间的间距)/总列数
 88     CGFloat cellW=(self.frame.size.width-leftM-rightM-(numberOfColumns-1)*columnM)/numberOfColumns;
 89 
 90     
 91     
 92     //用一个C语言的数组来存放所有列的最大的Y值
 93     CGFloat maxYOfColumns[numberOfColumns];
 94     for (int i=0; i<numberOfColumns; i++) {
 95         //初始化数组的数值全部为0
 96         maxYOfColumns[i]=0.0;
 97     }
 98     
 99     
100     //计算每个cell的fram
101     for (int i=0; i<numberOfCells; i++) {
102         
103         //(2)cell的高度
104         //询问代理i位置的高度
105         CGFloat cellH=[self heightAtIndex:i];
106         
107         //cell处在第几列(最短的一列)
108         NSUInteger cellAtColumn=0;
109         
110         //cell所处那列的最大的Y值(当前最短的那一列的最大的Y值)
111         //默认设置最短的一列为第一列(优化性能)
112         CGFloat maxYOfCellAtColumn=maxYOfColumns[cellAtColumn];
113         
114         //求出最短的那一列
115         for (int j=0; j<numberOfColumns; j++) {
116             if (maxYOfColumns[j]<maxYOfCellAtColumn) {
117                 cellAtColumn=j;
118                 maxYOfCellAtColumn=maxYOfColumns[j];
119             }
120         }
121         
122         //(3)cell的位置(X,Y)
123         //cell的X=左边的间距+列号*(cell的宽度+每列之间的间距)
124         CGFloat cellX=leftM+cellAtColumn*(cellW +columnM);
125         //cell的Y,先设定为0
126         CGFloat cellY=0;
127         if (maxYOfCellAtColumn==0.0) {//首行
128             cellY=topM;
129         }else
130         {
131             cellY=maxYOfCellAtColumn+rowM;
132         }
133         
134         //设置cell的frame并添加到数组中
135         CGRect cellFrame=CGRectMake(cellX, cellY, cellW, cellH);
136         [self.cellFrames addObject:[NSValue valueWithCGRect:cellFrame]];
137         
138         //更新最短那一列的最大的Y值
139         maxYOfColumns[cellAtColumn]=CGRectGetMaxY(cellFrame);
140         
141         //显示cell
142 //        YYWaterflowViewCell *cell=[self.dadaSource waterflowView:self cellAtIndex:i];
143 //        cell.frame=cellFrame;
144 //        [self addSubview:cell];
145     }
146     
147     //设置contentSize
148     CGFloat contentH=maxYOfColumns[0];
149     for (int i=1; i<numberOfColumns; i++) {
150         if (maxYOfColumns[i]>contentH) {
151             contentH=maxYOfColumns[i];
152         }
153     }
154     contentH += bottomM;
155     self.contentSize=CGSizeMake(0, contentH);
156 }
157 
158 /**
159  *  当UIScrollView滚动的时候也会调用这个方法
160  */
161 -(void)layoutSubviews
162 {
163     [super layoutSubviews];
164  
165     
166     //向数据源索要对应位置的cell
167     NSUInteger numberOfCells=self.cellFrames.count;
168     for (int i=0; i<numberOfCells; i++) {
169         //取出i位置的frame,注意转换
170         CGRect cellFrame=[self.cellFrames[i] CGRectValue];
171         
172         //优先从字典中取出i位置的cell
173         YYWaterflowViewCell *cell=self.displayingCells[@(i)];
174         
175         //判断i位置对应的frame在不在屏幕上(能否看见)
176         if ([self isInScreen:cellFrame]) {//在屏幕上
177             if (cell==nil) {
178                cell= [self.dadaSource waterflowView:self cellAtIndex:i];
179                 cell.frame=cellFrame;
180                 [self addSubview:cell];
181                 
182                 //存放在字典中
183                 self.displayingCells[@(i)]=cell;
184             }
185             
186         }else //不在屏幕上
187         {
188             if (cell) {
189                 //从scrollView和字典中删除
190                 [cell removeFromSuperview];
191                 [self.displayingCells removeObjectForKey:@(i)];
192                 
193                 //存放进缓存池
194                 [self.reusableCells addObject:cell];
195             }
196         }
197     }
198 //       NSLog(@"%d",self.subviews.count);
199 }
200 
201 -(id)dequeueReusableCellWithIdentifier:(NSString *)identifier
202 {
203    __block YYWaterflowViewCell *reusableCell=nil;
204     [self.reusableCells enumerateObjectsUsingBlock:^(YYWaterflowViewCell *cell, BOOL *stop) {
205         if ([cell.identifier isEqualToString:identifier]) {
206             reusableCell=cell;
207             *stop=YES;
208         }
209     }];
210     
211     if (reusableCell) {//从缓存池中移除(已经用掉了)
212         [self.reusableCells removeObject:reusableCell];
213     }
214     return reusableCell;
215 }
216 
217 #pragma mark cell的事件处理
218 -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
219 {
220     //如果没有点击事件的代理方法,那么就直接返回
221     if (![self.delegate respondsToSelector:@selector(waterflowView:didSelectAtIndex:)])
222         return;
223     
224     //获得手指在屏幕上点击的触摸点
225     UITouch *touch=[touches anyObject];
226 //    CGPoint point=[touch locationInView:touch.view];
227     CGPoint point=[touch locationInView:self];
228     
229     __block NSNumber *selectIndex=nil;
230     [self.displayingCells enumerateKeysAndObjectsUsingBlock:^(id key, YYWaterflowViewCell *cell, BOOL *stop) {
231         if (CGRectContainsPoint(cell.frame, point)) {
232             selectIndex=key;
233             *stop=YES;
234         }
235     }];
236     if (selectIndex) {
237         //需要转换
238         [self.delegate waterflowView:self didSelectAtIndex:selectIndex.unsignedIntegerValue];
239     }
240     
241 }
242 #pragma mark-私有方法
243 /**
244  *  判断一个人cell的frame有没有显示在屏幕上
245  */
246 -(BOOL)isInScreen:(CGRect)frame
247 {
248 //    return (CGRectGetMaxY(frame)>self.contentOffset.y)&&(CGRectGetMaxY(frame)<self.contentOffset.y+self.frame.size.height);
249     return (CGRectGetMaxY(frame) > self.contentOffset.y) &&
250     (CGRectGetMinY(frame) < self.contentOffset.y + self.frame.size.height);
251 
252 }
253 -(CGFloat)marginForType:(YYWaterflowViewMarginType)type
254 {
255     if ([self.delegate respondsToSelector:@selector(waterflowView:marginForType:)]) {
256        return  [self.delegate waterflowView:self marginForType:type];
257     }else
258     {
259         return YYWaterflowViewDefaultMargin;
260     }
261 }
262 
263 -(NSUInteger)numberOfColumns
264 {
265     if ([self.dadaSource respondsToSelector:@selector(numberOfColumnsInWaterflowView:)]) {
266         return [self.dadaSource numberOfColumnsInWaterflowView:self];
267     }else
268     {
269         return  YYWaterflowViewDefaultNumberOfClunms;
270     }
271 }
272 
273 -(CGFloat)heightAtIndex:(NSUInteger)index
274 {
275     if ([self.delegate respondsToSelector:@selector(waterflowView:heightAtIndex:)]) {
276         return [self.delegate waterflowView:self heightAtIndex:index];
277     }else
278     {
279         return YYWaterflowViewDefaultCellH;
280     }
281 }
282 @end
复制代码

实现效果:

点击对应的cell,能够监听并对点击事件进行处理。

 

三、补充说明

示例代码:

说明:

touch.view指的是子控件(单个cell)以这个cell的左上角为(0,0)进行坐标计算

self指的是整个瀑布流,以整个瀑布流的左上角为(0,0)进行坐标计算

打印查看:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值