scrollToRowAtIndexPath:atScrollPosition导致表视图“跳转”
我的应用程序具有聊天function,我正在喂这样的新消息:
[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];
但是,当我添加一个新的消息(发送和接收,结果是相同的),我的表视图“跳”怪异:
为什么我会得到这个奇怪的“跳跃”?
好的,我明白了。 正如你所说,这个问题与自动调整单元格有关。 我使用了两个技巧来完成工作(我的代码在Swift中,但是应该很容易翻译回ObjC):
1)等待表格animation完成后再采取进一步行动。 这可以通过在CATransaction.begin()
和CATransaction.commit()
之间封装更新表内的代码来完成。 我在CATransaction上设置了完成块 – 在animation完成后,代码将运行。
2)强制表格视图在滚动到底部之前呈现单元格。 我通过增加表的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() }
将UITableViewRowAnimationNone
更改为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];