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

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

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

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

https://vid.me/edgW

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

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

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

  • Запустите проект.
  • Прокрутите список до появления ячейки 10.
  • Подождите до 5 секунд, чтобы ячейка перезагрузилась (она становится фиолетовой).
  • Прокрутка вверх.

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

Ответ 1

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

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

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

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

Ответ 2

У меня тоже была эта проблема, и я использовал решение из 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;
    }
}

Ответ 3

Э-э... это тяжелая проблема.

Позвольте взглянуть на facebook. У них была такая же проблема с их графиком, и они в конечном итоге сделали это в каком-то веб-виде.

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

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

Ответ 4

Я столкнулся с одной и той же проблемой, моя таблица работает нормально до перезагрузки tableview. Поэтому я нашел решение, использую только rowHeight, не оцененную высоту. Также, если у вас разная высота. Поэтому, пожалуйста, предоставьте полный код, чтобы я предоставил решение. У меня есть ячейка, которая напоминает страницу instagram. Я прохожу расчетную высоту в методе highforrow, который отлично работает. Но расчетная высота не работает хорошо в этой ситуации. Если вы используете код ниже, он работает нормально. Попробуйте.

self.tableView.rowHeight = 75 //it will be your dynamic height
//self.tableView.estimatedRowHeight = 75

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