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

时间:2016-02-09 11:39:15

标签: ios uitableview 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];

然而,我的桌面视图"跳跃"奇怪的是,当我添加一条新消息时(发送和接收,两者的结果相同):

enter image description here

为什么我会变得这么奇怪"跳跃"?

5 个答案:

答案 0 :(得分:17)

好的,我明白了。正如您所说,问题与自动调整大小单元有关。我使用两个技巧来使事情有效(我的代码在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()
}

答案 1 :(得分:1)

UITableViewRowAnimationBottom更改为UITableViewRowAnimationNone并尝试

答案 2 :(得分:0)

试试这个!

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];

答案 3 :(得分:0)

对于Swift 3和4

向下滚动到表格的底部在表格视图中添加新项目时自动查看仅在tableView函数中添加以下行我的工作

tableView.scrollToRow(at:IndexPath,at:.bottom,animated:true)

例如,

在我的情况下,我只有一个部分所以0用于部分,我有orderItems列表所以对于最后一个索引我使用orderItems.count - 1

tableView.scrollToRow(at:[0,orderItems.count - 1],at:.bottom,animated:true)

答案 4 :(得分:-1)

我刚刚在ios 11上发现这个问题不再存在。因此,在向表格视图添加行,然后使用where date= date_retrieved滚动到该行时,不再有内容跳转。

此外,在ios 10上调用scrollToRowAtIndexPath并使用animated = false修复了内容跳转