UITableView scrollToRowAtIndexPath прокручивает до неправильного смещения с оценкой RowHeight на iOS 7
Я использую метод estimatedRowHeight
из UITableView в iOS 7, который отлично работает для быстрой загрузки UITableView с 5000 строк переменной высоты.
Мой UITableView состоит из 50 разделов. Каждая секция имеет 100 рядов с переменной высотой.
В начале я использую estimatedRowHeight
для быстрой загрузки, но после этого, когда я вызываю scrollToRowAtIndexPath
, мой UITableView прокручивается до неправильного смещения. Я могу понять, почему это так, потому что у него есть estimatedRowHeight
, пока я не прокручу всю таблицу, и правильные высоты ячейки не будут установлены в методе делегата heightForRowAtIndexPath
.
Любое решение?
Ответы
Ответ 1
К сожалению, эту проблему следует ожидать при использовании estimatedRowHeight
в вашем коде с таким низким значением. Когда вы scrollToRowAtIndexPath
, он не активно вычисляет правильный размер по мере продвижения. Основная причина заключается в том, что если вы прокручиваете из раздела 1 в раздел 2, то можно было бы правильно вычислить правильное положение "на лету" и estimatedRowHeight
ячеек, если это было относительно новое устройство. Любые более старые устройства были бы поставлены на колени, и даже любые новые были бы также, если бы вам пришлось обрабатывать 5000 ячеек, например.
Возможно, решение вашей проблемы может состоять в том, чтобы увеличить константу estimatedRowHeight
, чтобы устройству не приходилось делать столько работы.
Ответ 2
Когда вызывается scrollToRowAtIndexPath
, высота всех ячеек текущей позиции и целевого смещения не вычисляется. Только некоторые из них.
Вместо этого UITableView использует estimatedRowHeight
для вычисления смещения цели, что приводит к неправильному смещению.
У меня такая же проблема, и я нашел небольшой трюк (который мне не очень нравится) для вычисления точной высоты ячейки только один раз после начального relaodData
. Я вставил две строки ниже:
tableView.reloadData()
// only for the initial reloadData
let numSections = tableView.numberOfSections
let numRowsInLastSection = tableView.numberOfRowsInSection(numSections-1)
// scrolls to the last row in the tableView
tableView.scrollToRowAtIndexPath(NSIndexPath(forRow: numRows-1, inSection: numSections-1), atScrollPosition: .Bottom, animated: false)
// back again to the original position(which is 0 for this is only called right after the initial reloadData)
tableView.scrollToRowAtIndexPath(NSIndexPath(forRow: 0, inSection: 0), atScrollPosition: .Top, animated: false)
Это приводит к тому, что tableView появляется на экране поздно, но я думаю, что это приемлемо, а не замораживать пользовательский интерфейс после появления tableView. Это даже лучше, когда вы вызываете API в начале, потому что это похоже на небольшую задержку в сети, а не на отставание пользовательского интерфейса.
После этого tableView переходит к точному расположению ячеек.
Да, мне тоже не нравится это решение: |
EDIT:
Единственная причина, по которой я это сделал, - вычислить фактическую высоту строки, вызвав cellForRowAtIndexPath:
, но я обнаружил, что при задании правильной оценкиHight для каждой строки методом delegate estimatedHeightForRowAtIndexPath:
вместо статического значения UITableView.estimatedRowHeight
решает проблему.
Наконец, я решил кэшировать высоты строк с willDisplayCell:forRowAtIndexPath:
на диск и использовать это значение на estimatedHeightForRowAtIndexPath:
.
Таким образом, estimatedHeightForRowAtIndexPath:
для всех строк вызывается в начале и scrollToRowAtIndexPath
работает хорошо.
Ответ 3
Это не самое приятное решение, но я использую обходной путь для этой проблемы, кто делает трюк. Всегда обновляйте оценочную оценку RowHeight до самой высокой вычислительной ячейки, а затем используйте что-то вроде этого:
- Прокрутка содержимого таблицыView для смещения нуля.
-
Завершите вызов scrollToRowAtIndexPath для индексации нулевого пути.
[self.tableView setContentOffset:CGPointZero animated:YES];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]
atScrollPosition:UITableViewScrollPositionTop
animated:YES];
});
В результате tableView должен прокручивать вверх до конца плавно.
Ответ 4
Решение для меня состояло в том, чтобы установить estimatedRowHeight to 0
Ответ 5
Не было твердого решения, но для меня было приемлемым выполнение прокрутки без анимации, которая хорошо работала в том смысле, что она прокручивается до ожидаемой ячейки с правильным смещением, несмотря на то, что упоминается в http://www.openradar.me/20829131.
self.tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition:.Top, animated: false)
Ответ 6
Кажется, что это работает после того, как представление было составлено системой. Я вызываю scrollToRowAtIndexPath с правильными результатами в VC viewDidAppear. Это, конечно, не очень красиво, потому что он прокручивается, когда представление уже видно...
Ответ 7
попробуйте добавить этот код в -cellForRowAtIndexPath: перед возвратом ячейки
[cell layoutIfNeeded]
Ответ 8
Это решило мою проблему
let oldContentSize = tableView.contentSize
tableView.scrollToRow(at: indexPath, at: .top, animated: true)
// Called again when tableView contentSize change
if !tableView.contentSize.equalTo(oldContentSize) {
tableView.scrollToRow(at: indexPath, at: .top, animated: true)
}