UITableView 在单元格刷新时滚动到顶部
UITableView Scrolls to Top on Cell Refresh
我有一个 UITableView,其中的单元格动态调整大小以适应其中的 UITextView。每当键入一个键时,单元格都会检查计算出的高度是否增加了,就像换行符一样,因此它可以告诉 table 单元格的高度需要重新计算。我用这段代码来做到这一点。
- (void) createNoteCellViewDidUpdate: (CreateNoteCell*) cell {
CGFloat newHeight = [self tableView:self.tableView heightForRowAtIndexPath:CreateNoteCellIndexPath];
if (newHeight != CGRectGetHeight(cell.contentView.frame)) {
[self.tableView beginUpdates];
[self.tableView endUpdates]; // <- HERE IS WHERE THE CONTENT OFFSET CHANGES
}
}
调整大小和 table 边界符合预期。但是,它不仅仅是动画高度的变化,它还会滚动到顶部。这可以在此处看到,当按下 return 键时。
通过键值观察,我发现当滚动视图的contentSize发生变化时,滚动视图contentOffset被设置。并且当调用 endUpdates 方法时,contentSize 会发生多次变化。当它发生变化时,它会从正常高度变为相当大的高度,然后再回到正常高度。我想知道它是否会因此而达到顶峰。我不知道从这里去哪里。
只是猜测...
在任何更改之前保存 uitableview 的 contentOffset
。之后再设置。
CGFloat contentOffset = self.tableView.contentOffset;
然后在更改之后
self.tableView.contentOffset = contentOffset;
哇,Josh Gafni 的回答帮了大忙;他值得投票。我的解决方案是基于他的。这仍然感觉像是 hack,所以如果有人还有更好的方法来做到这一点,我仍然很想听听。
首先我保存内容偏移量,然后我开始更新。
CGPoint offset = self.tableView.contentOffset;
[self.tableView beginUpdates];
[self.tableView endUpdates];
这会为单元格的高度变化设置动画并调整所有帧以适应约束。
接下来,我从 tableView 的层中删除所有动画,因此到顶部的动画停止。然后我将 contentOffst 重置为之前的状态。
[self.tableView.layer removeAllAnimations];
[self.tableView setContentOffset:offset animated:NO];
最后,我让 tableView 处理动画向下滚动,这样单元格的底部就在键盘上方。
[self.tableView scrollToRowAtIndexPath:CreateNoteCellIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
瞧,效果很好。
更简化的解决方案(更改 textView 时添加通知观察器),Swift-版本。主要技巧是使用 UIView.setAnimationsEnabled
.
func textViewDidChanged(notification: NSNotification) {
UIView.setAnimationsEnabled(false)
let contentOffset = self.tableView.contentOffset
tableView.beginUpdates()
tableView.endUpdates()
tableView.contentOffset = contentOffset
UIView.setAnimationsEnabled(true)
}
这是我的 UITableView 扩展,效果很好。在 Swift 2.1。基于已接受的答案。
extension UITableView
{
func reloadDataAnimatedKeepingOffset()
{
let offset = contentOffset
UIView.setAnimationsEnabled(false)
beginUpdates()
endUpdates()
UIView.setAnimationsEnabled(true)
layoutIfNeeded()
contentOffset = offset
}
}
我有一个 UITableView,其中的单元格动态调整大小以适应其中的 UITextView。每当键入一个键时,单元格都会检查计算出的高度是否增加了,就像换行符一样,因此它可以告诉 table 单元格的高度需要重新计算。我用这段代码来做到这一点。
- (void) createNoteCellViewDidUpdate: (CreateNoteCell*) cell {
CGFloat newHeight = [self tableView:self.tableView heightForRowAtIndexPath:CreateNoteCellIndexPath];
if (newHeight != CGRectGetHeight(cell.contentView.frame)) {
[self.tableView beginUpdates];
[self.tableView endUpdates]; // <- HERE IS WHERE THE CONTENT OFFSET CHANGES
}
}
调整大小和 table 边界符合预期。但是,它不仅仅是动画高度的变化,它还会滚动到顶部。这可以在此处看到,当按下 return 键时。
通过键值观察,我发现当滚动视图的contentSize发生变化时,滚动视图contentOffset被设置。并且当调用 endUpdates 方法时,contentSize 会发生多次变化。当它发生变化时,它会从正常高度变为相当大的高度,然后再回到正常高度。我想知道它是否会因此而达到顶峰。我不知道从这里去哪里。
只是猜测...
在任何更改之前保存 uitableview 的 contentOffset
。之后再设置。
CGFloat contentOffset = self.tableView.contentOffset;
然后在更改之后
self.tableView.contentOffset = contentOffset;
哇,Josh Gafni 的回答帮了大忙;他值得投票。我的解决方案是基于他的。这仍然感觉像是 hack,所以如果有人还有更好的方法来做到这一点,我仍然很想听听。
首先我保存内容偏移量,然后我开始更新。
CGPoint offset = self.tableView.contentOffset;
[self.tableView beginUpdates];
[self.tableView endUpdates];
这会为单元格的高度变化设置动画并调整所有帧以适应约束。
接下来,我从 tableView 的层中删除所有动画,因此到顶部的动画停止。然后我将 contentOffst 重置为之前的状态。
[self.tableView.layer removeAllAnimations];
[self.tableView setContentOffset:offset animated:NO];
最后,我让 tableView 处理动画向下滚动,这样单元格的底部就在键盘上方。
[self.tableView scrollToRowAtIndexPath:CreateNoteCellIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
瞧,效果很好。
更简化的解决方案(更改 textView 时添加通知观察器),Swift-版本。主要技巧是使用 UIView.setAnimationsEnabled
.
func textViewDidChanged(notification: NSNotification) {
UIView.setAnimationsEnabled(false)
let contentOffset = self.tableView.contentOffset
tableView.beginUpdates()
tableView.endUpdates()
tableView.contentOffset = contentOffset
UIView.setAnimationsEnabled(true)
}
这是我的 UITableView 扩展,效果很好。在 Swift 2.1。基于已接受的答案。
extension UITableView
{
func reloadDataAnimatedKeepingOffset()
{
let offset = contentOffset
UIView.setAnimationsEnabled(false)
beginUpdates()
endUpdates()
UIView.setAnimationsEnabled(true)
layoutIfNeeded()
contentOffset = offset
}
}