scrollToRowAtIndexPath:atScrollPosition 导致 table 视图变为 "jump"
scrollToRowAtIndexPath:atScrollPosition causing table view to "jump"
我的应用程序具有聊天功能,我正在像这样输入新消息:
[self.tableView beginUpdates];
[messages addObject:msg];
[self.tableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:messages.count - 1 inSection:1]] withRowAnimation:UITableViewRowAnimationBottom];
[self.tableView endUpdates];
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:messages.count - 1 inSection:1] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
但是,当我添加一条新消息时,我的 table 视图 "jumps" 很奇怪(无论是发送还是接收,结果都是一样的):
为什么我会变得这么奇怪 "jump"?
将UITableViewRowAnimationBottom
更改为UITableViewRowAnimationNone
并尝试
试试这个!
UITableViewRowAnimation rowAnimation = UITableViewRowAnimationTop;
UITableViewScrollPosition scrollPosition = UITableViewScrollPositionTop;
[self.tableView beginUpdates];
[messages addObject:msg];
[self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:rowAnimation];
[self.tableView endUpdates];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:scrollPosition animated:YES];
// Fixes the cell from blinking (because of the transform, when using translucent cells)
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
好的,我明白了。正如您所说,问题与自动调整单元格有关。我使用了两个技巧来使事情正常进行(我的代码在 Swift 中,但应该很容易翻译回 ObjC):
1) 等待 table 动画结束后再采取进一步的行动。这可以通过将更新 table 的代码包含在 CATransaction.begin()
和 CATransaction.commit()
之间的块中来完成。我在 CATransaction 上设置了完成块——该代码将在动画完成后 运行。
2) 强制 table 视图在滚动到底部之前呈现单元格。我通过少量增加 table 的 contentOffset
来做到这一点。这会导致新插入的单元格出列,并计算其高度。滚动完成后(我等待它使用上面的方法 (1) 完成),我最终调用 tableView.scrollToRowAtIndexPath
。
代码如下:
override func viewDidLoad() {
super.viewDidLoad()
// Use auto-sizing for rows
tableView.estimatedRowHeight = 40
tableView.rowHeight = UITableViewAutomaticDimension
tableView.dataSource = self
}
func chatManager(chatManager: ChatManager, didAddMessage message: ChatMessage) {
messages.append(message)
let indexPathToInsert = NSIndexPath(forRow: messages.count-1, inSection: 0)
CATransaction.begin()
CATransaction.setCompletionBlock({ () -> Void in
// This block runs after the animations between CATransaction.begin
// and CATransaction.commit are finished.
self.scrollToLastMessage()
})
tableView.beginUpdates()
tableView.insertRowsAtIndexPaths([indexPathToInsert], withRowAnimation: .Bottom)
tableView.endUpdates()
CATransaction.commit()
}
func scrollToLastMessage() {
let bottomRow = tableView.numberOfRowsInSection(0) - 1
let bottomMessageIndex = NSIndexPath(forRow: bottomRow, inSection: 0)
guard messages.count > 0
else { return }
CATransaction.begin()
CATransaction.setCompletionBlock({ () -> Void in
// Now we can scroll to the last row!
self.tableView.scrollToRowAtIndexPath(bottomMessageIndex, atScrollPosition: .Bottom, animated: true)
})
// scroll down by 1 point: this causes the newly added cell to be dequeued and rendered.
let contentOffset = tableView.contentOffset.y
let newContentOffset = CGPointMake(0, contentOffset + 1)
tableView.setContentOffset(newContentOffset, animated: true)
CATransaction.commit()
}
对于 Swift 3 和 4
用于向下滚动到 table 的底部 当在 table 视图中添加新项目时自动查看 tableView 功能添加以下行它的作品我
tableView.scrollToRow(位于:IndexPath,位于:.bottom,动画:true)
例如
在我的例子中,我只有一个部分,所以 0 用于部分,我有 orderItems 列表,所以对于最后一个索引,我使用 orderItems.count - 1
tableView.scrollToRow(在:[0,orderItems.count - 1],在:.bottom,动画:真)
我刚刚发现在 ios 11 这个问题不再存在。因此,当向 table 视图添加一行然后使用 scrollToRow(at:)
滚动到它时,不再有内容跳转。
此外,在 ios 10 上调用带有 animated=false 的 scrollToRowAtIndexPath 修复了内容跳转
我的应用程序具有聊天功能,我正在像这样输入新消息:
[self.tableView beginUpdates];
[messages addObject:msg];
[self.tableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:messages.count - 1 inSection:1]] withRowAnimation:UITableViewRowAnimationBottom];
[self.tableView endUpdates];
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:messages.count - 1 inSection:1] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
但是,当我添加一条新消息时,我的 table 视图 "jumps" 很奇怪(无论是发送还是接收,结果都是一样的):
为什么我会变得这么奇怪 "jump"?
将UITableViewRowAnimationBottom
更改为UITableViewRowAnimationNone
并尝试
试试这个!
UITableViewRowAnimation rowAnimation = UITableViewRowAnimationTop;
UITableViewScrollPosition scrollPosition = UITableViewScrollPositionTop;
[self.tableView beginUpdates];
[messages addObject:msg];
[self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:rowAnimation];
[self.tableView endUpdates];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:scrollPosition animated:YES];
// Fixes the cell from blinking (because of the transform, when using translucent cells)
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
好的,我明白了。正如您所说,问题与自动调整单元格有关。我使用了两个技巧来使事情正常进行(我的代码在 Swift 中,但应该很容易翻译回 ObjC):
1) 等待 table 动画结束后再采取进一步的行动。这可以通过将更新 table 的代码包含在 CATransaction.begin()
和 CATransaction.commit()
之间的块中来完成。我在 CATransaction 上设置了完成块——该代码将在动画完成后 运行。
2) 强制 table 视图在滚动到底部之前呈现单元格。我通过少量增加 table 的 contentOffset
来做到这一点。这会导致新插入的单元格出列,并计算其高度。滚动完成后(我等待它使用上面的方法 (1) 完成),我最终调用 tableView.scrollToRowAtIndexPath
。
代码如下:
override func viewDidLoad() {
super.viewDidLoad()
// Use auto-sizing for rows
tableView.estimatedRowHeight = 40
tableView.rowHeight = UITableViewAutomaticDimension
tableView.dataSource = self
}
func chatManager(chatManager: ChatManager, didAddMessage message: ChatMessage) {
messages.append(message)
let indexPathToInsert = NSIndexPath(forRow: messages.count-1, inSection: 0)
CATransaction.begin()
CATransaction.setCompletionBlock({ () -> Void in
// This block runs after the animations between CATransaction.begin
// and CATransaction.commit are finished.
self.scrollToLastMessage()
})
tableView.beginUpdates()
tableView.insertRowsAtIndexPaths([indexPathToInsert], withRowAnimation: .Bottom)
tableView.endUpdates()
CATransaction.commit()
}
func scrollToLastMessage() {
let bottomRow = tableView.numberOfRowsInSection(0) - 1
let bottomMessageIndex = NSIndexPath(forRow: bottomRow, inSection: 0)
guard messages.count > 0
else { return }
CATransaction.begin()
CATransaction.setCompletionBlock({ () -> Void in
// Now we can scroll to the last row!
self.tableView.scrollToRowAtIndexPath(bottomMessageIndex, atScrollPosition: .Bottom, animated: true)
})
// scroll down by 1 point: this causes the newly added cell to be dequeued and rendered.
let contentOffset = tableView.contentOffset.y
let newContentOffset = CGPointMake(0, contentOffset + 1)
tableView.setContentOffset(newContentOffset, animated: true)
CATransaction.commit()
}
对于 Swift 3 和 4
用于向下滚动到 table 的底部 当在 table 视图中添加新项目时自动查看 tableView 功能添加以下行它的作品我
tableView.scrollToRow(位于:IndexPath,位于:.bottom,动画:true)
例如 在我的例子中,我只有一个部分,所以 0 用于部分,我有 orderItems 列表,所以对于最后一个索引,我使用 orderItems.count - 1
tableView.scrollToRow(在:[0,orderItems.count - 1],在:.bottom,动画:真)
我刚刚发现在 ios 11 这个问题不再存在。因此,当向 table 视图添加一行然后使用 scrollToRow(at:)
滚动到它时,不再有内容跳转。
此外,在 ios 10 上调用带有 animated=false 的 scrollToRowAtIndexPath 修复了内容跳转