UITableViewCell контент мерцает при перезагрузке ячеек по отдельности
У меня есть табличное представление, связанное с NSFetchedResultController
(т.е. загрузка данных, а также отслеживание изменений в данных привязано к FRC)
Я не пользуюсь AutoLayout
в моих клетках (из-за огромного падения производительности это вводит в iOS 8). Я выкладываю содержимое своих клеток вручную в ячейках (используя -(void)layoutSubviews
). Кроме того, высота строк рассчитывается на основе содержимого и должным образом кэшируется / аннулируется.
Если какое-либо условие, связанное с моими данными, изменяется, связанные ячейки обновляются индивидуально (с целым -(void)controllerWillChangeContent:...
через -(void)controllerDidChangeContent:...
реализованы методы делегата) анимация для обновления строки: UITableViewRowAnimationNone
Проблема здесь в том, что мои ячейки имеют прозрачный фон, и я вижу некоторый визуальный шум (скорее всего, фактическая ячейка растягивается вертикально, я не могу сказать наверняка, потому что они действительно кратковременны и недолговечны) во время [self.tableView reloadRowsAtIndexPaths:...];
,
Я перепробовал много вещей безрезультатно!
Вот то, что я попробовал, но это не работает:
- Внедрение
-(CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
, возвращая точное значение для предполагаемой высоты. - установка
self.tableView.rowHeight=UITableViewAutomaticDimension;
, очень помогает, но не исправляет это. - Отключение анимации при
[self.tableView beginUpdates];
и включение после[self.tableView endUpdates];
- Удаление всех подпредставлений из содержимого ячеек в
-(void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
Вещи, которые немного помогают:
- Создание непрозрачных ячеек (т.е. установка цвета фона для ячеек). как ни странно, артефакты, кажется, находятся под фактическим содержанием клетки.
Больше информации
- Большинство содержимого моих ячеек являются узлами из AsyncDisplayKit (ASTextNode, ASImageNode), но заменяют их своими
UIKit
коллеги не решают проблему. - Все мои визуальные обновления происходят в главном потоке. Я всегда в этом уверен.
- Проблема не вездесуща, но существует чаще, чем нет. Похоже, они происходят чаще после того, как вставлены вторые клетки, если это помогает
- Регистрация метода
-(void)layoutSubviews
в моих ячейках видно, что ячейки с условием обновления перезагружаются 3 раза подряд при каждом обновлении, в отличие от других ячеек, которые обновляются только один раз. Я не заставляю[cell layoutIfNeeded];
или же[cell setNeedsLayout];
в любом месте. - Перезагрузка всей таблицы с помощью
[self.tableView reloadData];
это не вариант для меня.
Дополнительная информация
- Создание непрозрачных клеток приводит к тому, что клетки выкладываются только один раз! странно!
В конце, я извиняюсь, что не могу поделиться каким-либо реальным кодом, потому что это не тестовый проект, а сложность реализаций делает бесполезным совместное использование кода, если он не понят в целом.
Спасибо за ваше время.
6 ответов
Если кто-то сталкивался с такой же проблемой:
Если вы рассчитываете высоту вашей ячейки и ее элементов, и вы зависите от NSIndexPath
для запроса каких-либо данных или условий всегда проверяйте правильность пути индекса (не nil
). Большинство UITableView
методы, которые возвращают путь индекса (например, -(NSIndexPath *)indexPathForCell:..
и т. д.) может вернуться nil
значения и будет сбивать вас по спирали, которая отлаживает представления.
В моем случае у меня был метод, чтобы определить, должна ли моя ячейка иметь заголовок, и для этого я проверил, является ли это первая ячейка или условие изменилось с предыдущей ячейки. проблема была indexPath.row == 0
верно, даже если путь индекса на самом деле nil
(это концептуальная проблема в Objective-C, где nil
это 0). поэтому на короткое время мои клетки подумали, что у них есть заголовок!
Я чувствую себя глупо, не проверяя nil
индексные пути, но я думаю, что когда-нибудь это может кому-нибудь помочь.
Я также столкнулся с той же проблемой мерцания UITableViewCell при использовании reloadRowsAtIndexPath, поэтому я сделал следующее:
[UIView setAnimationsEnabled:NO];
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil]
withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];
[UIView setAnimationsEnabled:YES];
Приведенный выше фрагмент не будет содержать анимацию в ячейках при перезагрузке ячейки.
Да, вы можете добиться аналогичного результата из ответа @Sandy, используя performWithoutAnimation
(Swift Version)
UIView.performWithoutAnimation {
self.tableView.reloadRows(at: [indexPath], with: .none)
}
В быстром я использую это, и это уменьшает мерцание
let visibleIndexs = self.ContentTableview.indexPathsForVisibleRows! as NSArray
print(visibleIndexs)
for indx in visibleIndexs {
if self.imgDownloadedIndexs!.containsObject(indx) {
UIView.setAnimationsEnabled(false)
self.ContentTableview.beginUpdates()
self.ContentTableview.reloadRowsAtIndexPaths([indx as! NSIndexPath], withRowAnimation:.None)
self.ContentTableview.endUpdates()
UIView.setAnimationsEnabled(true)
self.imgDownloadedIndexs?.removeObject(indx)
}
Удаление метода rowHeightAtIndexPath решит эту проблему. убедитесь, что вы установили некоторую фиксированную высоту ячейки таблицы в раскадровке.
Пользовательская ячейка tableView не была задействована и мерцала. Это было из-за клеточной анимации. После добавления приведенного ниже кода ячейка становится доступной и работает нормально. Этот случай происходит нормально, а также может возникнуть во время выполнения UITestCase.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
UIView.performWithoutAnimation {
self.tableView.reloadRows(at: [indexPath], with: .none)
}
return cell
}