我有一个表视图,显示我通过网络获取的消息。
当有新消息进入时,应将其添加到底部的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会像这样自动滚动?
答案 0 :(得分:1)
我也有这个问题。 NSTableView和UITableView可能类似......他们的默认滚动行为都是SUCK。 TableView不能用作电子表格样式编辑器, 所以多年来我已经添加了数千行代码来实现它 像电子表格一样工作一种。 我希望Apple能够创建一个NSTableView的NSSpreadsheetView子类来修复所有这些东西: - 光标键导航单元格 - 合理的滚动行为 - 附加小区选择
还希望看到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
}
答案 1 :(得分:0)
我认为您需要将行动画更改为无 -
[self.tableView
insertRowsAtIndexPaths:indexPaths
withRowAnimation:
UITableViewRowAnimationNone];
答案 2 :(得分:0)
试试这个
[self.tableView scrollToRowAtIndexPath:indexpath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
您也可以将位置更改为middile,top或none。