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

Тем не менее, мое табличное представление странно "прыгает", когда я добавляю новое сообщение (при отправке и получении, результат одинаков для обоих):

Почему я получаю этот странный "прыжок"?

5 ответов

Решение

Хорошо, я понял это. Как вы говорите, проблема связана с авторазмером ячеек. Я использовал два трюка, чтобы все заработало (мой код написан на 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()
}

+ Изменить 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];

Для Свифта 3 и 4

для прокрутки вниз к нижней части таблицы. Просмотр автоматически при добавлении нового элемента в табличное представление только в функции table View.

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

например, в моем случае у меня есть только один раздел, поэтому 0 используется для раздела, и у меня есть список orderItems, поэтому для последнего индекса я использую orderItems.count - 1

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

Я только что узнал, что на ios 11 эта проблема больше не существует. Таким образом, больше нет скачка содержимого при добавлении строки в табличное представление и последующей прокрутке к нему с помощью scrollToRow(at:),

Кроме того, на ios 10 вызов scrollToRowAtIndexPath с animated=false исправляет скачок содержимого

Другие вопросы по тегам