插入新行时 TableView 滚动到中间

Posted

技术标签:

【中文标题】插入新行时 TableView 滚动到中间【英文标题】:TableView scrolls to middle when a new row is inserted 【发布时间】:2013-11-22 17:29:43 【问题描述】:

我有一个表格视图,它显示了我通过网络获取的消息。

当有新消息进来时,它应该被添加到底部的tableview中。

当有新消息进来时,它会正确地添加到 tableview 的底部,但 tableview 会立即滚动到中间。 (所以如果我现在说有 100 个单元格,那么单元格 50 现在将位于滚动视图的中间)。

奇怪的是,只有在插入之前的滚动点位于 tableview 的下半部分时才会发生这种情况。

所以,如果我正在查看 99 个单元格中的第 10 个单元格,并且我添加了一行,它会被添加到底部就好了。

但是,如果我正在查看 99 个单元格中的第 75 个单元格,并且我添加了一行,则滚动位置会再次跳到中间(~单元格 50)。

这是我向 tableview 添加新消息的代码:

[self.tableView beginUpdates];
[self.messages addObject:message];

NSArray *indexPaths = @[[NSIndexPath indexPathForRow:(self.messages.count - 1) inSection:0]];

[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];

为什么tableview会这样自动滚动?

【问题讨论】:

你不想滚动你的tableview?? @hussainShabbir 它在没有任何用户交互的情况下滚动。当我添加一个新行时,我不希望它自动滚动到中间,它现在正在这样做。 @Jeff 解决这个问题好运吗?我有同样的问题。使用自我调整大小的单元格,它就像疯了一样跳跃。 【参考方案1】:

我也有这个问题。 NSTableView 和 UITableView 可能很相似……它们的默认滚动行为都很糟糕。 TableView 不是为用作电子表格样式编辑器而设计的, 所以多年来我已经添加了数千行代码来实现它 像电子表格一样工作某种。 我希望 Apple 只创建一个 NSTableView 的 NSSpreadsheetView 子类来修复所有这些问题: - 光标键导航单元格 - 明智的滚动行为 - 添加 hoc 单元格选择

还希望看到 NSTableView 的 NSLogView 子类,其行为类似于 Console.app,带有搜索字段。

我的解决方案是添加几个类别方法:

@implementation NSTableView (VNSTableViewCategory)

-(NSInteger)visibleRow

   NSRect theRect = [self visibleRect];
   NSRange theRange = [self rowsInRect:theRect];
   if ( theRange.length == 0 )
      return -1;
   else if ( NSLocationInRange( [self editedRow], theRange ) )
      return [self editedRow];        
   else if ( NSLocationInRange( [self clickedRow], theRange ) )
      return [self clickedRow];      
   else if ( NSLocationInRange( [self selectedRow], theRange ) )
      return [self selectedRow];
   else
      return theRange.location + (theRange.length/2);


-(NSRange)visibleRows

   NSRect theRect = [self visibleRect];
   NSRange theRange = [self rowsInRect:theRect];
   return theRange;


-(void)scrollRowToVisibleTwoThirds:(NSInteger)row

   NSRect theVisRect = [self visibleRect];
   NSUInteger numRows = [self numberOfRows];   
   NSRange visibleRows = [self rowsInRect:theVisRect];
   //NSUInteger lastVisibleRow = NSMaxRange(visibleRows);
   if ( NSLocationInRange( row, visibleRows ) )
   
      if ( row - visibleRows.location < (visibleRows.length * 2 / 3) )
      
         // may need to scroll up
         if ( visibleRows.location == 0 )
            [self scrollRowToVisible:0];
         else if ((row - visibleRows.location) > 2 )
            return;
      
   

   NSRect theRowRect = [self rectOfRow:row];

   NSPoint thePoint  = theRowRect.origin;
   thePoint.y -= theVisRect.size.height / 4; // scroll to 25% from top

   if (thePoint.y < 0 )
      thePoint.y = 0;

   NSRect theLastRowRect = [self rectOfRow:numRows-1];
   if ( thePoint.y + theVisRect.size.height > NSMaxY(theLastRowRect) )
      [self scrollRowToVisible:numRows-1];
   else
   
      [self scrollPoint:thePoint]; // seems to be the 'preferred' method of doing this

      // kpk note: these other approaches cause redraw artifacts in many situations:
//      NSClipView *clipView = [[self enclosingScrollView] contentView];
//      [clipView scrollToPoint:[clipView constrainScrollPoint:thePoint]];
//      [[self enclosingScrollView] reflectScrolledClipView:clipView];
//      [self scrollRowToVisible:row];

//      [[[self enclosingScrollView] contentView] scrollToPoint:thePoint];
//      [[self enclosingScrollView] reflectScrolledClipView:[[self enclosingScrollView] contentView]];       
   


@end // NSTableView (VNSTableViewCategory)

用法示例:

  NSRange visRows = [toScenesTable visibleRows];
  visRows.length -= 2;
  if ( iAlwaysScroll == YES || !NSLocationInRange(row, visRows) )
  
     [toScenesTable scrollRowToVisibleTwoThirds:row]; // VNSTableViewCategory
  

【讨论】:

【参考方案2】:

我认为您需要将行动画更改为无-

 [self.tableView 
 insertRowsAtIndexPaths:indexPaths 
 withRowAnimation:
UITableViewRowAnimationNone];

【讨论】:

我尝试了所有的动画类型,结果都一样:插入后tableview向上滚动到中心。【参考方案3】:

试试这个

[self.tableView scrollToRowAtIndexPath:indexpath atScrollPosition:UITableViewScrollPositionBottom animated:YES];

您也可以将位置更改为 middile、top 或 none。

【讨论】:

以上是关于插入新行时 TableView 滚动到中间的主要内容,如果未能解决你的问题,请参考以下文章

在 tableview 中插入新行会重复最后一行

插入新行表1复制到表2选定字段后mysql触发器没有重复

在 tableView 中插入新行后保存成为第一响应者的 UITextField 文本

当我插入新行时,UITableView 正在跳跃

快速在表格视图中插入新行时应用程序崩溃?

TableView:是不是可以在不重新加载 tableview 或部分的情况下删除现有行并插入新行?