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

相关问题