首页 > 代码库 > 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 "YYViewController.h"10 #import "YYWaterflowView.h"11 #import "YYWaterflowViewCell.h"12 13 @interface YYViewController ()<YYWaterflowViewDelegate,YYWaterflowViewDataSource>14 15 @end16 17 @implementation YYViewController18 19 - (void)viewDidLoad20 {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 *)waterflowView34 {35 return 100;36 }37 -(NSUInteger)numberOfColumnsInWaterflowView:(YYWaterflowView *)waterflowView38 {39 return 3;40 }41 -(YYWaterflowViewCell *)waterflowView:(YYWaterflowView *)waterflowView cellAtIndex:(NSUInteger)index42 {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)index52 {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)type61 {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)index74 {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 @required30 /**31 * (1)一共有多少个数据32 */33 -(NSUInteger)numberOfCellsInWaterflowView:(YYWaterflowView *)waterflowView;34 /**35 * (2)返回index位置对应的cell36 */37 -(YYWaterflowViewCell *)waterflowView:(YYWaterflowView *)waterflowView cellAtIndex:(NSUInteger)index;38 39 //不要求强制实现40 @optional41 /**42 * (3)一共有多少列43 */44 -(NSUInteger)numberOfColumnsInWaterflowView:(YYWaterflowView *)waterflowView;45 46 @end47 48 49 /**50 * 2.代理方法51 */52 @protocol YYWaterflowViewDelegate <UIScrollViewDelegate>53 //不要求强制实现54 @optional55 /**56 * (1)第index位置cell对应的高度57 */58 -(CGFloat)waterflowView:(YYWaterflowView *)waterflowView heightAtIndex:(NSUInteger)index;59 /**60 * (2)选中第index位置的cell61 */62 -(void)waterflowView:(YYWaterflowView *)waterflowView didSelectAtIndex:(NSUInteger)index;63 /**64 * (3)返回间距65 */66 -(CGFloat)waterflowView:(YYWaterflowView *)waterflowView marginForType:(YYWaterflowViewMarginType)type;67 @end68 69 70 /**71 * 3.瀑布流控件72 */73 @interface YYWaterflowView : UIScrollView74 /**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 }else102 {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 //显示cell114 YYWaterflowViewCell *cell=[self.dadaSource waterflowView:self cellAtIndex:i];115 cell.frame=cellFrame;116 [self addSubview:cell];117 }118 119 //设置contentSize120 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)type132 {133 if ([self.delegate respondsToSelector:@selector(waterflowView:marginForType:)]) {134 return [self.delegate waterflowView:self marginForType:type];135 }else136 {137 return YYWaterflowViewDefaultMargin;138 }139 }140 141 -(NSUInteger)numberOfColumns142 {143 if ([self.dadaSource respondsToSelector:@selector(numberOfColumnsInWaterflowView:)]) {144 return [self.dadaSource numberOfColumnsInWaterflowView:self];145 }else146 {147 return YYWaterflowViewDefaultNumberOfClunms;148 }149 }150 151 -(CGFloat)heightAtIndex:(NSUInteger)index152 {153 if ([self.delegate respondsToSelector:@selector(waterflowView:heightAtIndex:)]) {154 return [self.delegate waterflowView:self heightAtIndex:index];155 }else156 {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个滚动条(水平方向上的滚动条被隐藏了,但是仍然存在)
优化思路:放入到缓存池。
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。