1. 程式人生 > >在iOS上實現瀑布流介面

在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,回收不可見的物件。