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

UITableView scrollToRowAtIndexPath прокручивает до неправильного смещения с оценкой RowHeight на iOS 7

Я использую метод estimatedRowHeight из UITableView в iOS 7, который отлично работает для быстрой загрузки UITableView с 5000 строк переменной высоты.

Мой UITableView состоит из 50 разделов. Каждая секция имеет 100 рядов с переменной высотой. В начале я использую estimatedRowHeight для быстрой загрузки, но после этого, когда я вызываю scrollToRowAtIndexPath, мой UITableView прокручивается до неправильного смещения. Я могу понять, почему это так, потому что у него есть estimatedRowHeight, пока я не прокручу всю таблицу, и правильные высоты ячейки не будут установлены в методе делегата heightForRowAtIndexPath.

Любое решение?

4b9b3361

Ответ 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)
}