码迷,mamicode.com
首页 > 移动开发 > 详细

ios开发——实用技术篇&自定义Collection与使用

时间:2015-05-30 21:05:31      阅读:236      评论:0      收藏:0      [点我收藏+]

标签:

自定义Collection与使用
实现步骤
一、新建两个类
1.继承自UIScrollView的子类,比如iCocosWaterflowView
* 瀑布流显示控件,用来显示所有的瀑布流数据

2.继承自UIView的子类,比如iCocosWaterflowViewCell
* 代表着瀑布流数据中的一个单元(一个格子)

3.总结
iCocosWaterflowView和iCocosWaterflowViewCell的关系实际上类似于
UITableView和UITableViewCell的关系

二、设计iCocosWaterflowView的接口
1.模仿UITableView的接口来设计
* 设计一套数据源和代理方法

三、iCocosWaterflowView的实现
1.reloadData
* 作用:刷新数据
* 步骤:
1> 清空以前残余的数据
2> 计算所有新数据对应的frame

2.layoutSubviews
* 作用:显示和移除子控件
* 步骤:
1> 检测每一个数据对应的frame在不在屏幕上(用户能不能看见)
2> 如果这个数据对应的frame在屏幕上:向数据源索要这个数据对应的cell,添加这个cell到iCocosWaterflowView中显示
3> 如果这个数据对应的frame不在屏幕上:从iCocosWaterflowView中移除这个数据对应的cell,并将这个cell添加到缓存池中
 
 
View.h文件
技术分享
 1 #import <UIKit/UIKit.h>
 2 
 3 typedef enum {
 4     iCocosWaterflowViewMarginTypeTop,
 5     iCocosWaterflowViewMarginTypeBottom,
 6     iCocosWaterflowViewMarginTypeLeft,
 7     iCocosWaterflowViewMarginTypeRight,
 8     iCocosWaterflowViewMarginTypeColumn, // 每一列
 9     iCocosWaterflowViewMarginTypeRow, // 每一行
10 } iCocosWaterflowViewMarginType;
11 
12 @class iCocosWaterflowView, iCocosWaterflowViewCell;
13 
14 /**
15  *  数据源方法
16  */
17 @protocol iCocosWaterflowViewDataSource <NSObject>
18 @required
19 /**
20  *  一共有多少个数据
21  */
22 - (NSUInteger)numberOfCellsInWaterflowView:(iCocosWaterflowView *)waterflowView;
23 /**
24  *  返回index位置对应的cell
25  */
26 - (iCocosWaterflowViewCell *)waterflowView:(iCocosWaterflowView *)waterflowView cellAtIndex:(NSUInteger)index;
27 
28 @optional
29 /**
30  *  一共有多少列
31  */
32 - (NSUInteger)numberOfColumnsInWaterflowView:(iCocosWaterflowView *)waterflowView;
33 @end
34 
35 /**
36  *  代理方法
37  */
38 @protocol iCocosWaterflowViewDelegate <UIScrollViewDelegate>
39 @optional
40 /**
41  *  第index位置cell对应的高度
42  */
43 - (CGFloat)waterflowView:(iCocosWaterflowView *)waterflowView heightAtIndex:(NSUInteger)index;
44 /**
45  *  选中第index位置的cell
46  */
47 - (void)waterflowView:(iCocosWaterflowView *)waterflowView didSelectAtIndex:(NSUInteger)index;
48 /**
49  *  返回间距
50  */
51 - (CGFloat)waterflowView:(iCocosWaterflowView *)waterflowView marginForType:(iCocosWaterflowViewMarginType)type;
52 @end
53 
54 /**
55  *  瀑布流控件
56  */
57 @interface iCocosWaterflowView : UIScrollView
58 /**
59  *  数据源
60  */
61 @property (nonatomic, weak) id<iCocosWaterflowViewDataSource> dataSource;
62 /**
63  *  代理
64  */
65 @property (nonatomic, weak) id<iCocosWaterflowViewDelegate> delegate;
66 
67 /**
68  *  刷新数据(只要调用这个方法,会重新向数据源和代理发送请求,请求数据)
69  */
70 - (void)reloadData;
71 
72 /**
73  *  cell的宽度
74  */
75 - (CGFloat)cellWidth;
76 
77 /**
78  *  根据标识去缓存池查找可循环利用的cell
79  */
80 - (id)dequeueReusableCellWithIdentifier:(NSString *)identifier;
81 @end
View Code

 

View.m文件

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

 

Cell.h文件

技术分享
1 #import <UIKit/UIKit.h>
2 
3 @interface iCocosWaterflowViewCell : UIView
4 @property (nonatomic, copy) NSString *identifier;
5 @end
View Code

使用方法:

1:新建一个Cell模型

技术分享
1 #import <Foundation/Foundation.h>
2 
3 @interface iCocosShop : NSObject
4 @property (nonatomic, assign) CGFloat w;
5 @property (nonatomic, assign) CGFloat h;
6 @property (nonatomic, copy) NSString *img;
7 @property (nonatomic, copy) NSString *price;
8 @end
View Code

2:定义一个集成自上面的Cell的Cell

技术分享
1 #import "iCocosWaterflowViewCell.h"
2 @class iCocosWaterflowView, iCocosShop;
3 
4 @interface iCocosShopCell : iCocosWaterflowViewCell
5 + (instancetype)cellWithWaterflowView:(iCocosWaterflowView *)waterflowView;
6 
7 @property (nonatomic, strong) iCocosShop *shop;
8 @end
View Code

实现这个Cell:

技术分享
 1 #import "iCocosShopCell.h"
 2 #import "iCocosWaterflowView.h"
 3 #import "UIImageView+WebCache.h"
 4 #import "iCocosShop.h"
 5 
 6 @interface iCocosShopCell()
 7 @property (weak, nonatomic) UIImageView *imageView;
 8 @property (weak, nonatomic) UILabel *priceLabel;
 9 @end
10 
11 @implementation iCocosShopCell
12 
13 
14 + (instancetype)cellWithWaterflowView:(iCocosWaterflowView *)waterflowView
15 {
16     static NSString *ID = @"SHOP";
17     iCocosShopCell *cell = [waterflowView dequeueReusableCellWithIdentifier:ID];
18     if (cell == nil) {
19         cell = [[iCocosShopCell alloc] init];
20         cell.identifier = ID;
21     }
22     return cell;
23 }
24 
25 - (id)initWithFrame:(CGRect)frame
26 {
27     self = [super initWithFrame:frame];
28     if (self) {
29         
30         UIImageView *imageView = [[UIImageView alloc] init];
31         [self addSubview:imageView];
32         self.imageView = imageView;
33         
34         UILabel *priceLabel = [[UILabel alloc] init];
35         priceLabel.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.3];
36         priceLabel.textAlignment = NSTextAlignmentCenter;
37         priceLabel.textColor = [UIColor whiteColor];
38         [self addSubview:priceLabel];
39         self.priceLabel = priceLabel;
40     }
41     return self;
42 }
43 
44 - (void)setShop:(iCocosShop *)shop
45 {
46     _shop = shop;
47     
48     self.priceLabel.text = shop.price;
49     [self.imageView sd_setImageWithURL:[NSURL URLWithString:shop.img] placeholderImage:[UIImage imageNamed:@"loading"]];
50 }
51 
52 - (void)layoutSubviews
53 {
54     [super layoutSubviews];
55     
56     self.imageView.frame = self.bounds;
57     
58     CGFloat priceX = 0;
59     CGFloat priceH = 25;
60     CGFloat priceY = self.bounds.size.height - priceH;
61     CGFloat priceW = self.bounds.size.width;
62     self.priceLabel.frame = CGRectMake(priceX, priceY, priceW, priceH);
63 }
View Code

3:在控制器中直接使用:

技术分享
  1 #import "iCocosShopsViewController.h"
  2 #import "iCocosShopCell.h"
  3 #import "iCocosWaterflowView.h"
  4 #import "iCocosShop.h"
  5 #import "MJExtension.h"
  6 #import "MJRefresh.h"
  7 
  8 @interface iCocosShopsViewController ()<iCocosWaterflowViewDataSource, iCocosWaterflowViewDelegate>
  9 @property (nonatomic, strong) NSMutableArray *shops;
 10 @property (nonatomic, weak) iCocosWaterflowView *waterflowView;
 11 @end
 12 
 13 @implementation iCocosShopsViewController
 14 
 15 - (NSMutableArray *)shops
 16 {
 17     if (_shops == nil) {
 18         self.shops = [NSMutableArray array];
 19     }
 20     return _shops;
 21 }
 22 
 23 - (void)viewDidLoad
 24 {
 25     [super viewDidLoad];
 26     
 27     // 0.初始化数据
 28     NSArray *newShops = [iCocosShop objectArrayWithFilename:@"2.plist"];
 29     [self.shops addObjectsFromArray:newShops];
 30     
 31     // 1.瀑布流控件
 32     iCocosWaterflowView *waterflowView = [[iCocosWaterflowView alloc] init];
 33     waterflowView.backgroundColor = [UIColor redColor];
 34     // 跟随着父控件的尺寸而自动伸缩
 35     waterflowView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
 36     waterflowView.frame = self.view.bounds;
 37     waterflowView.dataSource = self;
 38     waterflowView.delegate = self;
 39     [self.view addSubview:waterflowView];
 40     self.waterflowView = waterflowView;
 41     
 42     // 2.继承刷新控件
 43 //    [waterflowView addFooterWithCallback:^{
 44 //        NSLog(@"进入上拉加载状态");
 45 //    }];
 46     
 47 //    [waterflowView addHeaderWithCallback:^{
 48 //        NSLog(@"进入下拉加载状态");
 49     //    }];
 50     
 51     [waterflowView addHeaderWithTarget:self action:@selector(loadNewShops)];
 52     [waterflowView addFooterWithTarget:self action:@selector(loadMoreShops)];
 53 }
 54 
 55 - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
 56 {
 57 //    NSLog(@"屏幕旋转完毕");
 58     [self.waterflowView reloadData];
 59 }
 60 
 61 - (void)loadNewShops
 62 {
 63     static dispatch_once_t onceToken;
 64     dispatch_once(&onceToken, ^{
 65         // 加载1.plist
 66         NSArray *newShops = [iCocosShop objectArrayWithFilename:@"1.plist"];
 67         [self.shops insertObjects:newShops atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, newShops.count)]];
 68     });
 69     
 70     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
 71         // 刷新瀑布流控件
 72         [self.waterflowView reloadData];
 73         
 74         // 停止刷新
 75         [self.waterflowView headerEndRefreshing];
 76     });
 77 }
 78 
 79 - (void)loadMoreShops
 80 {
 81     static dispatch_once_t onceToken;
 82     dispatch_once(&onceToken, ^{
 83         // 加载3.plist
 84         NSArray *newShops = [iCocosShop objectArrayWithFilename:@"3.plist"];
 85         [self.shops addObjectsFromArray:newShops];
 86     });
 87     
 88     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
 89         
 90         // 刷新瀑布流控件
 91         [self.waterflowView reloadData];
 92         
 93         // 停止刷新
 94         [self.waterflowView footerEndRefreshing];
 95     });
 96 }
 97 
 98 #pragma mark - 数据源方法
 99 - (NSUInteger)numberOfCellsInWaterflowView:(iCocosWaterflowView *)waterflowView
100 {
101     return self.shops.count;
102 }
103 
104 - (iCocosWaterflowViewCell *)waterflowView:(iCocosWaterflowView *)waterflowView cellAtIndex:(NSUInteger)index
105 {
106     iCocosShopCell *cell = [iCocosShopCell cellWithWaterflowView:waterflowView];
107     
108     cell.shop = self.shops[index];
109     
110     return cell;
111 }
112 
113 - (NSUInteger)numberOfColumnsInWaterflowView:(iCocosWaterflowView *)waterflowView
114 {
115     if (UIInterfaceOrientationIsPortrait(self.interfaceOrientation)) {
116         // 竖屏
117         return 3;
118     } else {
119         return 5;
120     }
121 }
122 
123 #pragma mark - 代理方法
124 - (CGFloat)waterflowView:(iCocosWaterflowView *)waterflowView heightAtIndex:(NSUInteger)index
125 {
126     iCocosShop *shop = self.shops[index];
127     // 根据cell的宽度 和 图片的宽高比 算出 cell的高度
128     return waterflowView.cellWidth * shop.h / shop.w;
129 }
View Code

注:这里还需要引入第三方库和相应的工具类

 

ios开发——实用技术篇&自定义Collection与使用

标签:

原文地址:http://www.cnblogs.com/iCocos/p/4540959.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!