在iOS上實現瀑布流界麵
前陣子需要做一個需求,在iPhone上實現瀑布流效果。
第一眼看到這個需求,我想到的兩種解決方案分別是:
1. 使用多個UITableView,然後控製它們同時滾動;
2. 使用一個UIScrollView,然後參考UITableView的實現自己做一個符合需求並且以後可以重用的控件。
我首先嚐試了第一個方案,並且Google過控製多個UITableView同時滾動的代碼,在StackOverflow裏麵找到一段蠻詳細的代碼了,不過在複雜的用戶操作下,仍然會出現滾動不同步的情況。
最終,我放棄了這個方案。
而第二個方案的關鍵點就在於參考UITableView實現時,如何重用單元格。
下麵是我實現的重用代碼:
- (void)onScroll { for (int i = 0; i < self.columns; ++i) { NSUInteger basicVisibleRow = 0; WaterFlowViewCell *cell = nil; CGRect cellRect = CGRectZero; NSMutableArray *singleRectArray = [self.cellRectArray objectAtIndex:i]; NSMutableArray *singleVisibleArray = [self.visibleCells objectAtIndex:i]; if (0 == [singleVisibleArray count]) { // There is no visible cells in current column now, find one. for (int j = 0; j < [singleRectArray count]; ++j) { cellRect = [(NSValue *)[singleRectArray objectAtIndex:j] CGRectValue]; if (![self canRemoveCellForRect:cellRect]) { WFIndexPath *indexPath = [WFIndexPath indexPathForRow:j inColumn:i]; basicVisibleRow = j; cell = [self.waterFlowDataSource waterFlowView:self cellForRowAtIndexPath:indexPath]; // nil ? cell.indexPath = indexPath; cell.frame = cellRect; if (!cell.superview) [self addSubview:cell]; NSLog(@"Cell Info : %@\n", cell); [singleVisibleArray insertObject:cell atIndex:0]; break; } } } else { cell = [singleVisibleArray objectAtIndex:0]; basicVisibleRow = cell.indexPath.row; } // Look back to load visible cells for (int j = basicVisibleRow - 1; j >= 0; --j) { cellRect = [(NSValue *)[singleRectArray objectAtIndex:j] CGRectValue]; if (![self canRemoveCellForRect:cellRect]) { WFIndexPath *indexPath = [WFIndexPath indexPathForRow:j inColumn:i]; if ([self containVisibleCellForIndexPath:indexPath]) { continue ; } cell = [self.waterFlowDataSource waterFlowView:self cellForRowAtIndexPath:indexPath]; // nil ? cell.indexPath = indexPath; cell.frame = cellRect; if (!cell.superview) [self addSubview:cell]; NSLog(@"Cell Info : %@\n", cell); [singleVisibleArray insertObject:cell atIndex:0]; } else { break; } } // Look forward to load visible cells for (int j = basicVisibleRow + 1; j < [singleRectArray count]; ++j) { cellRect = [(NSValue *)[singleRectArray objectAtIndex:j] CGRectValue]; if (![self canRemoveCellForRect:cellRect]) { WFIndexPath *indexPath = [WFIndexPath indexPathForRow:j inColumn:i]; if ([self containVisibleCellForIndexPath:indexPath]) { continue ; } cell = [self.waterFlowDataSource waterFlowView:self cellForRowAtIndexPath:indexPath]; // nil ? cell.indexPath = indexPath; cell.frame = cellRect; if (!cell.superview) [self addSubview:cell]; NSLog(@"Cell Info : %@\n", cell); [singleVisibleArray insertObject:cell atIndex:0]; } else { break; } } // Recycle invisible cells for (int j = 0; j < [singleVisibleArray count]; ++j) { cell = [singleVisibleArray objectAtIndex:j]; if ([self canRemoveCellForRect:cell.frame]) { [cell removeFromSuperview]; [self addReusableCell:cell]; [singleVisibleArray removeObject:cell]; --j; NSLog(@"Removable Cell Info : %@\n", cell); } } } }
主要思想就是,1. 找到一個需要展示的Cell;2. 以這個Cell開始,向前、向後推進,為需要展現出來的Cell分配;3. 遍曆可見Cell,回收不可見的對象。
最後,把代碼稍微做了抽離,弄了個小Demo,放到GitHub:https://github.com/siqin/WaterFlow
最後更新:2017-04-02 17:28:39