UITableView插入行而不滚动

时间:2011-05-03 16:38:30

标签: iphone objective-c uitableview

我有一个从Web服务中提取的数据列表。我刷新数据,我想在当前数据上方的表视图中插入数据,但我想在tableview中保持当前的滚动位置。

现在我通过在当前部分上方插入一个部分来完成此操作,但它实际上是插入,向上滚动,然后我必须手动向下滚动。我尝试在此之前禁用桌面上的滚动,但这也不起作用。

这看起来不稳定,看起来很黑。有什么更好的方法呢?

[tableView beginUpdates];

[tableView insertSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationNone];

[tableView endUpdates];

NSUInteger iContentOffset = 200; //height of inserted rows

[tableView setContentOffset:CGPointMake(0, iContentOffset)];

6 个答案:

答案 0 :(得分:17)

如果我理解你的使命,

我是这样做的:

if(self.tableView.contentOffset.y > ONE_OR_X_ROWS_HEIGHT_YOUDECIDE
{

    self.delayOffset = self.tableView.contentOffset;
    self.delayOffset = CGPointMake(self.delayOffset.x, self.delayOffset.y+ insertedRowCount * ONE_ROW_HEIGHT);

    [self.tableView reloadData];

    [self.tableView setContentOffset:self.delayOffset animated:NO];    


}else
{
    [self.tableView insertRowsAtIndexPath:indexPathArray   WithRowAnimation:UITableViewRowAnimationTop];

}

使用此代码,如果用户位于表的中间而不是顶部,则uitableview将重新加载新行而不进行动画而不进行滚动。 如果用户位于表格的顶部,他将看到行插入动画。

请注意代码,我假设行的高度相等,如果没有,只计算要插入的所有新行的高度。 希望有所帮助。

答案 1 :(得分:8)

我发现获得所需行为的最佳方法是根本不为插入设置动画。动画导致了波动。

相反,我打电话:

[tableView reloadData];

// set the content offset to the height of inserted rows 
// (2 rows * 44 points = 88 in this example)
[tableView setContentOffset:CGPointMake(0, 88)]; 

这使重新加载与内容偏移更改同时出现。

答案 2 :(得分:3)

对于寻找 Swift 3 + 解决方案的其他观众:

您需要保存UITableView的当前偏移量,然后重新加载,然后在UITableView上设置偏移量。

func reloadTableView(_ tableView: UITableView) {
    let contentOffset = tableView.contentOffset
    tableView.reloadData()
    tableView.layoutIfNeeded()
    tableView.setContentOffset(contentOffset, animated: false)
}

被称为:reloadTableView(self.tableView)

答案 3 :(得分:1)

只需在setContentOffset之前致电endUpdates,这对我有用。

[tableView setContentOffset:CGPointMake(0, iContentOffset)];
[tableView endUpdates];

答案 4 :(得分:1)

我正在使用自我调整大小的细胞,估计的行高非常没用,因为细胞的大小可能会有很大差异。所以计算contentOffset并不适合我。

我最终得到的解决方案非常简单,完美无缺。 首先,我应该提一下,我有一些帮助方法,允许我获取索引路径的数据元素,反之亦然 - 数据元素的索引路径。

-(void) loadMoreElements:(UIRefreshControl *) refreshControl {
  NSIndexPath *topIndexPath = [NSIndexPath indexPathForRow:0 inSection:0]
  id topElement = [myModel elementAtIndexPath:topIndexPath];

  // Somewhere here you'll need to tell your model to get more data
  [self.tableView reloadData];

  NSIndexPath *indexPath = [myModel indexPathForElement:topElement];

  [self.tableView scrollToRowAtIndexPath:indexPath 
                        atScrollPosition:UITableViewScrollPositionTop 
                                animated:NO];

  [refreshControl endRefreshing];
}

答案 5 :(得分:1)

这里的答案都没有对我有用,所以我提出了我的解决方案。这个想法是当你下拉刷新表格视图(或者用新数据异步加载)时,新单元格应该静静地坐在桌面上,而不会干扰用户的当前偏移。所以这里有一个有效的解决方案(几乎是警告

var indexpathsToReload: [IndexPath] = [] //this should contain the new indexPaths
var height: CGFloat = 0.0
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) {
    UIView.performWithoutAnimation {

        self.tableview.reloadSections(NSIndexSet(index: 0) as IndexSet, with: .none) 
        self.tableview.layoutIfNeeded()
        indexpathsToReload.forEach({ (idx) in
            height += self.feed.rectForRow(at: idx).height
        })
        let afterContentOffset = self.tableview.contentOffset                             
        let newContentOffset = CGPoint(x: afterContentOffset.x, y: afterContentOffset.y + height)
        self.tableview.setContentOffset(newContentOffset, animated: false)
    }
}

CAVEAT(警告) 如果您的tableview不是" full"即它只有几个细胞。在这种情况下,您还需要增加tableview的contentSizecontentOffset。一旦我想出那个,我会更新这个答案。

<强>说明: 基本上,我们需要将contentOffset的{​​{1}}设置为重新加载之前的位置。为此,我们只需计算使用预先填充的tableView数组添加的所有新单元格的总高度(可以在获取新数据并将其添加到数据源时准备),这些是{{ 1}}用于新细胞。然后,我们使用indexPath使用所有这些新单元格的总高度,并在重新加载后将其设置为indexPaths rectForRow(at: indexPath)的{​​{1}}位置。 y不是必需的,但是我把它放在那里是因为我只需要给tableview一些时间来反弹它的原始位置,因为我正在进行#34;拉动刷新&# 34;办法。另请注意,在我的情况下,contentOffset值始终为tableView,因此我可以在那里使用硬编码DispatchQueue.main.asyncAfter