ios – scrollToRowAtIndexPath:atScrollPosition导致表视图“跳转”

我的应用程序有聊天功能,我正在喂这样的新消息:
[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)等待桌面动画完成,然后再采取进一步措施.这可以通过将代码更新到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()
}

相关文章

UITabBarController 是 iOS 中用于管理和显示选项卡界面的一...
UITableView的重用机制避免了频繁创建和销毁单元格的开销,使...
Objective-C中,类的实例变量(instance variables)和属性(...
从内存管理的角度来看,block可以作为方法的传入参数是因为b...
WKWebView 是 iOS 开发中用于显示网页内容的组件,它是在 iO...
OC中常用的多线程编程技术: 1. NSThread NSThread是Objecti...