Как я могу перезагружать элементы без удаления и вставки с помощью UITableViewDiffableDataSource?

Я реализую экран поиска в своем приложении, используя UITableViewDiffableDataSource. Каждая ячейка представляет результат поиска и выделяет совпадение при поиске в заголовке ячейки, вроде как окно Xcode Open Quickly выделяет части элементов результатов. По мере ввода текста в поле поиска я обновляю список результатов. Результаты перемещаются вверх и вниз по списку по мере изменения их релевантности.

Хитрость в том, что мне нужно заставить каждую ячейку повторно отображать каждый раз при изменении текста поиска, потому что новая строка поиска означает обновление выделенных частей заголовка ячейки. Но я не хочу анимировать удаление и вставку, потому что это все тот же элемент. Как я могу сообщить источнику данных с помощью снимка состояния, что ему необходимо перезагрузить ячейки?

Я объявляю источник данных так:

@property (retain) UITableViewDiffableDataSource<NSString *, SearchHit *> *dataSource;

SearchHitпредставляет один результат поиска; у него есть свойства для отображаемого заголовка и массив диапазонов, которые нужно выделить в заголовке. И это отменяетhash а также isEqual: так что каждая строка результатов однозначно идентифицируется.

Мой код выглядит примерно так:

-(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
  NSArray<SearchHit *> *hits = [self fetchHits:searchText];
  NSDiffableDataSourceSnapshot<NSString *, SearchHit *> *snap = [[[NSDiffableDataSourceSnapshot alloc] init] autorelease];
  [snap appendSectionsWithIdentifiers:@[@""]];
  [snap appendItemsWithIdentifiers:hits];
  [snap reloadItemsWithIdentifiers:hits];
  [self.dataSource applySnapshot:snap animatingDifferences:YES];
}

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

Эта статья Донни Уолса и связанная с ней ветка в Твиттере с участием Стива Брина предполагает, что способ исправить это - сделать так, чтобы тип идентификатора элемента представлял только свойства, необходимые для отображения ячейки. Итак, я обновилSearchHitсравнение хэша и равенства, чтобы включить выделенные части заголовка, чего раньше не было. Затем мне нужно было удалять и вставлять анимацию для всех ячеек при каждом обновлении, чего я не хочу.

Это похоже на то, что reloadItemsWithIdentifiers должен делать... верно?

Пример проекта здесь, на GitHub.

2 ответа

API источника данных diff может быть неподходящим инструментом для создания анимации самих ячеек. Он предназначен для анимации появления, исчезновения и упорядочения ячеек. Если в вашем источнике данных есть изменение, которое выражается в соответствии с Hashable, api увидит это как изменение и удалит / вставит и т. Д.

Я бы посоветовал удалить поисковый текст из идентификатора элемента и заставить каждую ячейку наблюдать за поисковым текстом и производить анимацию или перерисовывать независимо от источника данных.

Правильное решение этой проблемы на самом деле находится в именах API — объекты, которые вы передаете источнику данных, должны быть идентификаторами , такими как значения rowid из базы данных. В моем случае, когда идентификаторы элементов не представляют строки в базе данных, которые я могу найти, мне просто нужно сохранить состояние объектов в какой-то структуре поиска, чтобы при вызове reloadItemsWithIdentifiers, я получаю состояние каждой ячейки из этой структуры, а не из объекта, который передает мне источник данных.

Другие вопросы по тегам