iOS 實現瀑布流界面

前陣子需要做一個需求,在iPhone上實現瀑布流效果。

第一眼看到這個需求,我想到的兩種解決方案分別是:

1. 使用多個UITableView,然後控制它們同時滾動;

 2. 使用一個UIScrollView,然後參考UITableView的實現自己做一個符合需求並且以後可以重用的控件。


我首先嚐試了第一個方案,並且Google過控制多個UITableView同時滾動的代碼,在StackOverflow裏面找到一段蠻詳細的代碼了,不過在複雜的用戶操作下,仍然會出現滾動不同步的情況。

最終,我放棄了這個方案。


而第二個方案的關鍵點就在於參考UITableView實現時,如何重用單元格。

下面是我實現的重用代碼:

  1. - (void)onScroll  
  2. {  
  3.     for (int i = 0; i < self.columns; ++i) {  
  4.         NSUInteger basicVisibleRow = 0;  
  5.         WaterFlowViewCell *cell = nil;  
  6.         CGRect cellRect = CGRectZero;  
  7.           
  8.         NSMutableArray *singleRectArray = [self.cellRectArray objectAtIndex:i];  
  9.         NSMutableArray *singleVisibleArray = [self.visibleCells objectAtIndex:i];  
  10.           
  11.         if (0 == [singleVisibleArray count]) {  
  12.             // There is no visible cells in current column now, find one.  
  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];  
  17.                     basicVisibleRow = j;  
  18.                       
  19.                     cell = [self.waterFlowDataSource waterFlowView:self cellForRowAtIndexPath:indexPath]; // nil ?  
  20.                     cell.indexPath = indexPath;  
  21.                     cell.frame = cellRect;  
  22.                     if (!cell.superview) [self addSubview:cell];  
  23.                     NSLog(@"Cell Info : %@\n", cell);  
  24.                       
  25.                     [singleVisibleArray insertObject:cell atIndex:0];  
  26.                     break;  
  27.                 }  
  28.             }  
  29.         } else {  
  30.             cell = [singleVisibleArray objectAtIndex:0];  
  31.             basicVisibleRow = cell.indexPath.row;  
  32.         }  
  33.           
  34.         // Look back to load visible cells  
  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]) {  
  40.                     continue ;  
  41.                 }  
  42.                   
  43.                 cell = [self.waterFlowDataSource waterFlowView:self cellForRowAtIndexPath:indexPath]; // nil ?  
  44.                 cell.indexPath = indexPath;  
  45.                 cell.frame = cellRect;  
  46.                 if (!cell.superview) [self addSubview:cell];  
  47.                 NSLog(@"Cell Info : %@\n", cell);  
  48.                   
  49.                 [singleVisibleArray insertObject:cell atIndex:0];  
  50.             } else {  
  51.                 break;  
  52.             }  
  53.         }  
  54.           
  55.         // Look forward to load visible cells  
  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]) {  
  61.                     continue ;  
  62.                 }  
  63.                   
  64.                 cell = [self.waterFlowDataSource waterFlowView:self cellForRowAtIndexPath:indexPath]; // nil ?  
  65.                 cell.indexPath = indexPath;  
  66.                 cell.frame = cellRect;  
  67.                 if (!cell.superview) [self addSubview:cell];  
  68.                 NSLog(@"Cell Info : %@\n", cell);  
  69.                   
  70.                 [singleVisibleArray insertObject:cell atIndex:0];  
  71.             } else {  
  72.                 break;  
  73.             }  
  74.         }  
  75.           
  76.         // Recycle invisible cells  
  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];  
  83.                 --j;  
  84.                 NSLog(@"Removable Cell Info : %@\n", cell);  
  85.             }  
  86.         }  
  87.     }  
  88. }  

主要思想就是,1. 找到一個需要展示的Cell;2. 以這個Cell開始,向前、向後推進,爲需要展現出來的Cell分配;3. 遍歷可見Cell,回收不可見的對象。

最後,把代碼稍微做了抽離,弄了個小Demo,放到GitHub:https://github.com/siqin/WaterFlow在iOS上實現瀑布流界面

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章