it-roy-ru.com

UITableView с динамической высотой ячейки, прыгающей при прокрутке вверх после перезагрузки ячейки

У меня есть табличное представление с возможностью для каждой ячейки иметь собственную высоту, поэтому не подходит для использования rowHeight. Вместо этого сейчас я использую let indexSet = NSIndexSet(index: 10) и self.tableView.estimatedRowHeight = 75. Это означает, что он вызывает функцию sizeThatFits для ячейки, чтобы определить ее высоту. Это все хорошо работает.

Проблема тогда, когда вы перезагружаете ячейку, которая находится на экране. Прокрутка вниз, чтобы показать ячейку 10, например, затем перезагрузка ячейки 10, работает нормально. Но когда вы начинаете прокручивать назад вверх, мимо ячеек, которые вы уже видели, он возвращается к оценочному значению RowHeight для каждой ячейки, полностью игнорируя sizeThatFits, и поэтому перемещается по мере прокрутки. Для меня было бы невозможно дать точную или «достаточно хорошую» оценочную RowHeight, чтобы этот скачок не был заметен, поскольку мои ячейки смогут отображать либо строку текста, либо полное изображение - большая разница в размер.

Я показал этот эффект здесь:

https://vid.me/edgW

Я сделал много разных попыток сделать это, используя смесь heightForRowAtIndexPath, по оценкам HeightForRowAtIndexPath и т.д. Я пробовал разные советы по StackOverflow. Ничто не похоже на работу.

Я приложил очень простой пример проекта, где вы можете попробовать его сами:

https://www.dropbox.com/s/8f1rvkx9k23q6c1/tableviewtest.zip?dl=0

  1. Запустите проект.
  2. Прокрутите, пока не появится ячейка 10.
  3. Подождите 5 секунд, пока ячейка перезагрузится (она станет фиолетовой).
  4. Прокрутите вверх.

Стоит отметить - это происходит not, если ячейка не отображается при перезагрузке. Если он находится выше или ниже текущей точки прокрутки, все работает как положено.

14
Andrew

Такое поведение является ошибкой, если по какой-либо другой причине, кроме того, что оно больше не воспроизводится на iOS 9. Я уверен, что это не слишком утешительно.

Проблема в первую очередь связана с неточной оценкой, как сказал @NickCatib. Лучшее, что вы можете сделать на iOS 8, - это улучшить оценку. Метод, который многие рекомендовали, заключается в кэшировании высот в willDisplayCell и использовании их при последующих вызовах estimatedRowHeightAtIndexPath.

Вы могли бы смягчить поведение, не делая ничего, чтобы заставить UITableView отбросить свои кэши, например, изменив содержимое в ячейке напрямую, используя cellForRowAtIndexPath, а не перезагружая ее, если она отображается на экране. Однако это не поможет, если вам действительно нужно изменить высоту ячейки.

Боюсь, что ошибку нельзя легко исправить в табличном представлении, так как вы не можете контролировать макет. Эту ошибку можно легко обойти в подклассе UICollectionViewFlowLayout, изменив contentOffsetAdjustment во время аннулирования, хотя это может быть не так просто.

17
zwaldowski

У меня тоже была эта проблема, и я использовал решение от SO, которое сейчас не могу найти. Если я это сделаю, я добавлю ссылку. Вот решение:

Проблема с табличным представлением, не имеющим правильную оценку для высоты строк. Чтобы исправить это, сначала кэшируйте высоту в willDisplayCell, и в следующий раз используйте эту высоту.

Код

В viewDidLoad:

heightAtIndexPath = [NSMutableDictionary new];


- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    NSNumber *height = @(cell.frame.size.height);
    [heightAtIndexPath setObject:height forKey:indexPath];
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    return UITableViewAutomaticDimension;
}

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath{
    if([heightAtIndexPath objectForKey:indexPath]) {
        return [[heightAtIndexPath objectForKey:indexPath] floatValue];
    } else {
        return UITableViewAutomaticDimension;
    }
}
10
Pranoy C

Э-э ... это довольно сложная проблема.

Давайте посмотрим на Facebook. У них была та же проблема с их временной шкалой, и они закончили тем, что делали это в некотором веб-просмотре.

У меня была похожая проблема с какой-то временной шкалой, я использовал автоматическую высоту строки и имел эту проблему. Первое, что нужно было решить, это установить estimatedHeight как можно ближе к средней высоте ячейки. С этим довольно сложно справиться, поскольку у вас может быть текст (высота 50) или изображения + текст (высота 1500). Следующее, что нужно было сделать, чтобы улучшить это, это реализовать estimatedHeight forIndexPath, который в основном возвращает различную оценку высоты для различных indexPaths.

После этого было много других решений, но это было как можно ближе к переменным высотам (огромные различия).

0
Miknash