7

好的,所以我需要的是防止在當前可見行上方添加新元素時進行tableview滾動。我使用了NSFetchedResultsController和很多對象(比如10 000),並且當我沒有碰到contentOffset時,reloadData工作的非常流暢。當在頂部添加單元格時,使UITableView保持滾動位置

但是,當我試圖操縱contentOffset保持滾動位置插入新條目時,它開始凍結用戶界面像300毫秒這對我不利。

任何人都可以提出任何更好(更快)的解決方案,當在頂部添加新項目時,如何在同一個單元格中保留tableview?

這是我目前使用的代碼來跟蹤插入和移動contentOffset。它不支持動畫和不同的單元大小。

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject 
     atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type 
     newIndexPath:(NSIndexPath *)newIndexPath 
{ 
    switch(type) { 
     case NSFetchedResultsChangeInsert: 
      [_insertions addObject:@(newIndexPath.row)]; 
      break; 
    } 
} 


- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller { 
    _insertions = @[].mutableCopy; 
} 

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {   
    NSMutableArray *copy = _insertions.mutableCopy; 

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 

     NSSortDescriptor *lowestToHighest = [NSSortDescriptor sortDescriptorWithKey:@"self" ascending:YES]; 
     [copy sortUsingDescriptors:[NSArray arrayWithObject:lowestToHighest]]; 

     dispatch_sync(dispatch_get_main_queue(), ^{ 

      for (NSNumber *i in copy) { 
       [self p_delayedAddRowAtIndex:[i integerValue]]; 
      } 
      [self.tableView reloadData]; 
     }); 
    }); 
} 

- (CGFloat)p_firstRowHeight { 
    return [self tableView:[self tableView] heightForRowAtIndexPath:[NSIndexPath indexPathForRow:0 
                         inSection:0]]; 
} 

-(void)p_delayedAddRowAtIndex:(NSInteger)row { 

    NSIndexPath *firstVisibleIndexPath = [[self.tableView indexPathsForVisibleRows] firstObject]; 

    if (firstVisibleIndexPath.row >= row) { 

     CGPoint offset = [[self tableView] contentOffset]; 
     offset.y += [self firstRowHeight]; 

     if ([self.tableView visibleCells].count > self.tableView.frame.size.height/[self firstRowHeight]) { 
      [[self tableView] setContentOffset:offset]; 
     } 
    } 
} 
+0

這個工作:快照'controllerWillChangeContent'中的'firstVisibleIndexPath'。在'didChangeObject'中,保留在firstVisibleIndexPath之前插入了多少行的計數。然後在'controllerDidChangeContent'中,計算新行(通過添加count),重新加載tableView,然後'scrollToRowAtIndexPath'到新的indexPath。 – pbasdf 2014-11-22 12:11:44

+0

確保您的估計單元格大小未設置 – 2015-02-03 17:51:33

回答

2

好吧,經過一些反應後,我指出了正確的方向,我想出了這個解決方案。雖然有些醜陋的座標數學運算並且不支持不同的單元大小,但它的工作流暢。希望這會對某人有所幫助。

-(void)controllerWillChangeContent:(NSFetchedResultsController *)controller { 
    NSIndexPath *firstVisible = [[self.tableView indexPathsForVisibleRows] firstObject]; 
    self.topVisibleMessage = [self.fetchedResultsController objectAtIndexPath:firstVisible]; 

    NSIndexPath *topIndexPath = [self.fetchedResultsController indexPathForObject:self.topVisibleMessage]; 

    self.cellOffset = self.tableView.contentOffset.y - topIndexPath.row * [self firstRowHeight]; 
} 


-(void)controllerDidChangeContent:(NSFetchedResultsController *)controller { 
    [self.tableView reloadData]; 

    if (self.topVisibleMessage) { 
     NSIndexPath *topIndexPath = [self.fetchedResultsController indexPathForObject:self.topVisibleMessage]; 
     CGPoint point = {0, topIndexPath.row * [self firstRowHeight] + self.cellOffset}; 

     [self.tableView setContentOffset:point]; 
    } 
} 
0

您的任務可能熟悉很多新聞源應用程序列表視圖。你看過這些應用程序嗎?他們可能有某種解決方案。據我所知,保持表格視圖位置的唯一方法是scrollRectToVisible:animated:

許多社交網絡應用程序都有熟悉的方法在頂部插入新的單元格。當有更新時,在視圖頂部的小通知出現消息(「5個新項目」),輕按插入單元格並自動滾動到頂部。

+0

我一直在考慮視覺通知和添加單元格,但由於我使用NSFetchedResultsController,我沒有直接訪問數據源。任何想法我可以做到這一點? – kandreych 2014-11-21 15:13:09

+0

@ kandreych可能不會使用NSFetchedResultsController。 – Astoria 2014-11-21 15:29:49

+0

frc確實在我的應用程序中實現了巨大的後臺緩存和同步工作,因爲它基本上是rss閱讀器,所以我真的想保留它 – kandreych 2014-11-21 15:52:51

相關問題