scrollToRowAtIndexPath:atScrollPosition导致表视图"跳转"

Can*_*ğlu 18 uitableview ios ios9

我的应用程序有聊天功能,我正在输入这样的新消息:

[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];
Run Code Online (Sandbox Code Playgroud)

但是,当我添加新消息时,我的表视图"跳"很奇怪(发送和接收,结果在两者中都是相同的):

在此输入图像描述

为什么我会得到这种奇怪的"跳跃"?

Mac*_*tle 18

好的,我明白了.正如您所说,问题与自动调整大小单元有关.我使用了两个技巧来使事情有效(我的代码在Swift中,但它应该很容易转换回ObjC):

1)等待表动画完成后再采取进一步行动.这可通过包围该之间的块内更新表的代码来完成CATransaction.begin(),并CATransaction.commit().我在CATransaction上设置了完成块 - 该代码将在动画结束后运行.

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()
}
Run Code Online (Sandbox Code Playgroud)