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