Подтвердить что ты не робот

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

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

введите описание изображения здесь

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

4b9b3361

Ответ 1

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

Ответ 2

Измените UITableViewRowAnimationBottom на UITableViewRowAnimationNone и попробуйте

Ответ 3

Попробуйте это!

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