iOSで滝の流れを実現


先日はiPhoneで滝の流れを実現するための需要があった.
このニーズを一目で見て、私が考えている2つのソリューションは、次のとおりです.
1.複数のUItableViewを使用し、同時にスクロールするように制御します.
 2.UIscrollViewを使用し、UItableViewの実装を参照して、必要に応じて後で再利用できるコントロールを作成します.
私はまず最初の案を試みて、Googleは複数のUItable Viewを同時にスクロールするコードを制御しすぎて、StackOverflowの中で1段のとても詳しいコードを見つけましたが、複雑なユーザーの操作の下で、依然としてスクロールが同期していない情況が現れます.
結局、私はこの案を放棄した.
2つ目のシナリオのキーは、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 : %@
", 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 : %@
", 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 : %@
", 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 : %@
", cell); } } } }

主な考えは、1.展示が必要なセルを見つけることです.2.このセルで始まり、前、後ろに進み、必要なセルに割り当てる.3.表示されているセルを巡り、表示されていないオブジェクトを回収します.
最後に、コードを少し外して、小さなDemoを作って、GitHubに置きました.https://github.com/siqin/WaterFlow