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

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

一、简单说明

使用数据刷新框架:

该框架提供了两种刷新的方法,一个是使用block回调(存在循环引用问题,_ _weak),一个是使用调用。

  

问题:在进行下拉刷新之前,应该要清空之前的所有数据(在刷新数据这个方法中)。

移除正在显示的cell:

(1)把字典中的所有的值,都从屏幕上移除

(2)清除字典中的所有元素

(3)清除cell的frame,每个位置的cell的frame都要重新计算

(4)清除可复用的缓存池。

  该部分的代码如下:

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

二、刷新操作

  刷新操作的代码设计:

  

  1 //
  2 //  YYShopViewController.m
  3 //  06-瀑布流
  4 //
  5 //  Created by apple on 14-7-31.
  6 //  Copyright (c) 2014年 wendingding. All rights reserved.
  7 //
  8
  9 #import "YYShopViewController.h"
 10 #import "YYWaterflowView.h"
 11 #import "YYWaterflowViewCell.h"
 12 #import "YYShop.h"
 13 #import "YYShopCell.h"
 14 #import "MJExtension.h"
 15 #import "MJRefresh.h"
 16
 17 @interface YYShopViewController ()<YYWaterflowViewDataSource,YYWaterflowViewDelegate>
 18 @property(nonatomic,strong)NSMutableArray *shops;
 19 @property(nonatomic,strong)YYWaterflowView *waterflowView;
 20 @end
 21
 22 @implementation YYShopViewController
 23
 24 #pragma mark-懒加载
 25 -(NSMutableArray *)shops
 26 {
 27     if (_shops==nil) {
 28         _shops=[NSMutableArray array];
 29     }
 30     return _shops;
 31 }
 32 - (void)viewDidLoad
 33 {
 34     [super viewDidLoad];
 35
 36     //1.初始化数据
 37     NSArray *newShop=[YYShop objectArrayWithFilename:@"2.plist"];
 38     [self.shops addObjectsFromArray:newShop];
 39
 40     //2.创建一个瀑布流
 41     YYWaterflowView *waterflow=[[YYWaterflowView alloc]init];
 42     waterflow.autoresizingMask=UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
 43     waterflow.frame=self.view.bounds;
 44     waterflow.delegate=self;
 45     waterflow.dadaSource=self;
 46     [self.view addSubview:waterflow];
 47
 48     self.waterflowView=waterflow;
 49
 50     //3.实现数据的刷新
 51 //    [waterflow addFooterWithCallback:^{
 52 //        NSLog(@"上拉数据刷新");
 53 //    }];
 54 //
 55 //    [waterflow addHeaderWithCallback:^{
 56 //        NSLog(@"下拉数据刷新");
 57 //    }];
 58
 59     [waterflow addHeaderWithTarget:self action:@selector(loadNewShops)];
 60     [waterflow addFooterWithTarget:self action:@selector(loadMoreShops)];
 61 }
 62
 63 -(void)loadNewShops
 64 {
 65     //模拟,只执行一次刷新操作
 66     static dispatch_once_t onceToken;
 67     dispatch_once(&onceToken, ^{
 68         //加载1.plist文件
 69         NSArray *newShop=[YYShop objectArrayWithFilename:@"1.plist"];
 70         [self.shops insertObjects:newShop atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, newShop.count)]];
 71     });
 72
 73     //模拟网络延迟,2.0秒钟之后执行
 74     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
 75         //刷新数据
 76         [self.waterflowView reloadData];
 77
 78         //停止刷新
 79         [self.waterflowView headerEndRefreshing];
 80     });
 81 }
 82
 83 -(void)loadMoreShops
 84 {
 85     static dispatch_once_t onceToken;
 86     dispatch_once(&onceToken, ^{
 87         //加载1.plist文件
 88         NSArray *newShop=[YYShop objectArrayWithFilename:@"3.plist"];
 89         [self.shops addObjectsFromArray:newShop];
 90     });
 91
 92     //模拟网络延迟,2.0秒钟之后执行
 93     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
 94         //刷新数据
 95         [self.waterflowView reloadData];
 96
 97         //停止刷新
 98         [self.waterflowView footerEndRefreshing];
 99     });
100
101 }
102
103 #pragma mark-数据源方法
104 -(NSUInteger)numberOfCellsInWaterflowView:(YYWaterflowView *)waterflowView
105 {
106     return self.shops.count;
107 }
108 -(NSUInteger)numberOfColumnsInWaterflowView:(YYWaterflowView *)waterflowView
109 {
110     return 3;
111 }
112 -(YYWaterflowViewCell *)waterflowView:(YYWaterflowView *)waterflowView cellAtIndex:(NSUInteger)index
113 {
114     YYShopCell *cell=[YYShopCell cellWithwaterflowView:waterflowView];
115     cell.shop=self.shops[index];
116     return cell;
117 }
118
119
120 #pragma mark-代理方法
121 -(CGFloat)waterflowView:(YYWaterflowView *)waterflowView heightAtIndex:(NSUInteger)index
122 {
123     YYShop *shop=self.shops[index];
124     //根据Cell的宽度和图片的宽高比 算出cell的高度
125     return waterflowView.cellWidth*shop.h/shop.w;
126 }
127
128 -(void)waterflowView:(YYWaterflowView *)waterflowView didSelectAtIndex:(NSUInteger)index
129 {
130     NSLog(@"点击了第%d个cell",index);
131 }
132
133
134 @end

实现的刷新效果:

           

三、竖屏和横屏调整

设置横屏和竖屏。

屏幕旋转完毕会调用下面的方法。

因为scrollView的宽度是固定的,没有改变。

设置view的宽度和高度可以跟随者父控件自动拉伸。(在iPad开发中会将常用到)

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

时间: 2024-10-08 11:13:04

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

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 "YYViewControll

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