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 исправляет скачок содержимого