前阵子需要做一个需求,在iPhone上实现瀑布流效果。
第一眼看到这个需求,我想到的两种解决方案分别是:
1. 使用多个UITableView,然后控制它们同时滚动;
2. 使用一个UIScrollView,然后参考UITableView的实现自己做一个符合需求并且以后可以重用的控件。
我首先尝试了第一个方案,并且Google过控制多个UITableView同时滚动的代码,在StackOverflow里面找到一段蛮详细的代码了,不过在复杂的用户操作下,仍然会出现滚动不同步的情况。
最终,我放弃了这个方案。
而第二个方案的关键点就在于参考UITableView实现时,如何重用单元格。
下面是我实现的重用代码:
03 | for ( int i = 0; i < self.columns; ++i) { |
04 | NSUInteger basicVisibleRow = 0; |
05 | WaterFlowViewCell *cell = nil; |
06 | CGRect cellRect = CGRectZero; |
08 | NSMutableArray *singleRectArray = [self.cellRectArray objectAtIndex:i]; |
09 | NSMutableArray *singleVisibleArray = [self.visibleCells objectAtIndex:i]; |
11 | if (0 == [singleVisibleArray count]) { |
13 | for ( int j = 0; j < [singleRectArray count]; ++j) { |
14 | cellRect = [(NSValue *)[singleRectArray objectAtIndex:j] CGRectValue]; |
15 | if (![self canRemoveCellForRect:cellRect]) { |
16 | WFIndexPath *indexPath = [WFIndexPath indexPathForRow:j inColumn:i]; |
19 | cell = [self.waterFlowDataSource waterFlowView:self cellForRowAtIndexPath:indexPath]; |
20 | cell.indexPath = indexPath; |
21 | cell.frame = cellRect; |
22 | if (!cell.superview) [self addSubview:cell]; |
23 | NSLog(@ "Cell Info : %@\n" , cell); |
25 | [singleVisibleArray insertObject:cell atIndex:0]; |
30 | cell = [singleVisibleArray objectAtIndex:0]; |
31 | basicVisibleRow = cell.indexPath.row; |
35 | for ( int j = basicVisibleRow - 1; j >= 0; --j) { |
36 | cellRect = [(NSValue *)[singleRectArray objectAtIndex:j] CGRectValue]; |
37 | if (![self canRemoveCellForRect:cellRect]) { |
38 | WFIndexPath *indexPath = [WFIndexPath indexPathForRow:j inColumn:i]; |
39 | if ([self containVisibleCellForIndexPath:indexPath]) { |
43 | cell = [self.waterFlowDataSource waterFlowView:self cellForRowAtIndexPath:indexPath]; |
44 | cell.indexPath = indexPath; |
45 | cell.frame = cellRect; |
46 | if (!cell.superview) [self addSubview:cell]; |
47 | NSLog(@ "Cell Info : %@\n" , cell); |
49 | [singleVisibleArray insertObject:cell atIndex:0]; |
56 | for ( int j = basicVisibleRow + 1; j < [singleRectArray count]; ++j) { |
57 | cellRect = [(NSValue *)[singleRectArray objectAtIndex:j] CGRectValue]; |
58 | if (![self canRemoveCellForRect:cellRect]) { |
59 | WFIndexPath *indexPath = [WFIndexPath indexPathForRow:j inColumn:i]; |
60 | if ([self containVisibleCellForIndexPath:indexPath]) { |
64 | cell = [self.waterFlowDataSource waterFlowView:self cellForRowAtIndexPath:indexPath]; |
65 | cell.indexPath = indexPath; |
66 | cell.frame = cellRect; |
67 | if (!cell.superview) [self addSubview:cell]; |
68 | NSLog(@ "Cell Info : %@\n" , cell); |
70 | [singleVisibleArray insertObject:cell atIndex:0]; |
77 | for ( int j = 0; j < [singleVisibleArray count]; ++j) { |
78 | cell = [singleVisibleArray objectAtIndex:j]; |
79 | if ([self canRemoveCellForRect:cell.frame]) { |
80 | [cell removeFromSuperview]; |
81 | [self addReusableCell:cell]; |
82 | [singleVisibleArray removeObject:cell]; |
84 | NSLog(@ "Removable Cell Info : %@\n" , cell); |
主要思想就是,1. 找到一个需要展示的Cell;2. 以这个Cell开始,向前、向后推进,为需要展现出来的Cell分配;3. 遍历可见Cell,回收不可见的对象。最后,把代码稍微做了抽离,弄了个小Demo,放到GitHub:
https://github.com/siqin/WaterFlow