瀑布流

LWTWaterFlowView.h

 1 //
 2 //  LWTWaterFlowView.h
 3 //  瀑布流
 4 //
 5 //  Created by apple on 14-7-29.
 6 //  Copyright (c) 2014年 lwt. All rights reserved.
 7 //
 8 
 9 #import <UIKit/UIKit.h>
10 
11 typedef enum {
12     LWTWaterFlowViewMarginTypeTop, //
13     LWTWaterFlowViewMarginTypeLeft, //
14     LWTWaterFlowViewMarginTypeBotton, //
15     LWTWaterFlowViewMarginTypeRight, //
16     LWTWaterFlowViewMarginTypeRow, //
17     LWTWaterFlowViewMarginTypeColumn, //
18 } LWTWaterFlowViewMarginType;
19 
20 @class LWTWaterFlowView, LWTWaterFlowViewCell;
21 /**
22  *  瀑布流数据源
23  */
24 @protocol LWTWaterFlowViewDataSource <NSObject>
25 
26 /**
27  *  有多少个数据
28  */
29 - (NSUInteger)numberOfCellInWaterFlowView:(LWTWaterFlowView *)waterFlowView;
30 
31 /**  返回index位置对应的cell */
32 - (LWTWaterFlowViewCell *)waterFlowView:(LWTWaterFlowView *)waterFlowView cellAtIndex:(NSUInteger)index;
33 @optional
34 /**  一共有多少列 */
35 - (NSUInteger)numberOfColumnsInWaterFlowView:(LWTWaterFlowView *)waterFlowView;
36 @end
37 
38 /**
39  *  瀑布流代理
40  */
41 @protocol LWTWaterFlowViewDelegate <UIScrollViewDelegate>
42 @optional
43 /**  第index位置cell对应的高度 */
44 - (CGFloat)waterFlowView:(LWTWaterFlowView *)waterFlowView heightForCellAtIndex:(NSUInteger)index;
45 
46 /**  选中第index位置的cell */
47 - (void)waterFlowView:(LWTWaterFlowView *)waterFlowView didSelectForCellAtIndex:(NSUInteger)index;
48 /**
49  *  间距
50  */
51 - (CGFloat)waterFlowView:(LWTWaterFlowView *)waterFlowView marginForType:(LWTWaterFlowViewMarginType)type;
52 @end
53 
54 @interface LWTWaterFlowView : UIScrollView
55 /**
56  *  数据源
57  */
58 @property (nonatomic, weak) id<LWTWaterFlowViewDataSource> dataSource;
59 
60 /**
61  *  代理
62  */
63 @property (nonatomic, weak) id<LWTWaterFlowViewDelegate> delegate;
64 
65 /**
66  *  刷新数据(只要调用这个方法,会重新向数据源和代理发送请求,请求数据)
67  */
68 - (void)reloadData;
69 
70 /**
71  *  cell的宽度
72  */
73 - (CGFloat)cellWidth;
74 
75 /**
76  *  根据标识去缓存池查找可循环利用的cell
77  */
78 - (id) dequeueReusableCellWithIdentifier:(NSString *)identifier;
79 
80 @end
View Code

LWTWaterFlowView.m

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

LWTWaterFlowViewCell.h

//
//  LWTWaterFlowViewCell.h
//  瀑布流
//
//  Created by apple on 14-7-29.
//  Copyright (c) 2014年 lwt. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface LWTWaterFlowViewCell : UIView
@property (nonatomic, copy) NSString *identifier;

- (instancetype)initWithIdentifier:(NSString *)identifier;

@end
View Code

LWTWaterFlowViewCell.m

//
//  LWTWaterFlowViewCell.m
//  瀑布流
//
//  Created by apple on 14-7-29.
//  Copyright (c) 2014年 lwt. All rights reserved.
//

#import "LWTWaterFlowViewCell.h"

@implementation LWTWaterFlowViewCell

- (id)initWithIdentifier:(NSString *)identifier
{
    self = [super init];
    if (self) {
        self.identifier = identifier;
    }
    return self;
}
@end
View Code

 

posted on 2014-07-30 18:34  问苍天  阅读(126)  评论(0编辑  收藏  举报