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