UICollectionView анімація зміни даних


83

У своєму проекті я використовую UICollectionView для відображення сітки піктограм.

Користувач може змінити порядок, натиснувши сегментований елемент керування, який викликає вибірку з основних даних за допомогою іншого NSSortDescriptor.

Обсяг даних завжди однаковий, лише потрапляючи в різні розділи / рядки:

- (IBAction)sortSegmentedControlChanged:(id)sender {

   _fetchedResultsController = nil;
   _fetchedResultsController = [self newFetchResultsControllerForSort];

   NSError *error;
   if (![self.fetchedResultsController performFetch:&error]) {
       NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
   }

   [self.collectionView reloadData];
}

Проблема в тому, що reloadData не оживляє зміни, UICollectionView просто з'являється з новими даними.

Чи слід мені відстежувати, в якому комірці indexPath була до та після зміни, та використовувати [self.collectionView moveItemAtIndexPath: toIndexPath:] для виконання анімації для зміни, чи є кращий метод?

Я не надто захоплювався підкласом collectionViews, тому будь-яка допомога буде чудовою ...

Дякую, Білл.


Ви пробували обернути цей reloadDataдзвінок у блок анімації?
simon

Відповіді:


71

reloadData не анімує і не робить цього надійно, коли розміщується в блоці анімації UIView. Він хоче бути в блоці UICollecitonView performBatchUpdates, тому спробуйте щось більше на зразок:

[self.collectionView performBatchUpdates:^{
    [self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]];
} completion:^(BOOL finished) {
    // do something on completion 
}];

5
так, здається, це працює, але лише якщо у вас є номери розділів збереження ... інакше я отримую "недійсну кількість розділів. Кількість розділів, що містяться у поданні колекції після оновлення (10), повинна дорівнювати кількості розділи, що містяться у поданні колекції до оновлення (16) ". Я повинен вручну вставляти / видаляти розділи ... у будь-якому разі прийнято! Дякую.
Nimrod7,

1
Під "вручну" ви маєте на увазі виклики UICollectionView insertSections / moveSection: toSection / deleteSections? Або щось інше? (вибачте, поки що моє використання UICollectionView мало статичну кількість розділів)
Stripes

1
так за допомогою цих методів ... трохи складно реалізувати думку, потрібно пам'ятати шляхи покажчиків до і після оновлення, цифру, яку видалено, вставлено або переміщено ...
Nimrod7

12
Це не спрацювало для мого подання колекції з одного розділу. Я не отримував помилок, але це також не оживляло. Заміна -reloadSections:змушує це працювати.
paulmelnikow

9
Ця відповідь не є правильною, оскільки для мого випадку розміщення reloadData у perforBatchUpdates призведе до аварійного завершення роботи мого додатка та заяви, що кількість клітинок неоднакова до і після. використання reloadSections вирішило мою проблему. Документ Apple також вказує не викликати reloadData в блоці анімації
Wingzero,

145

Обгортання -reloadDataв , -performBatchUpdates:здається, не викликає уявлення колекції в один розділ анімувати.

[self.collectionView performBatchUpdates:^{
    [self.collectionView reloadData];
} completion:nil];

Однак цей код працює:

[self.collectionView performBatchUpdates:^{
    [self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]];
} completion:nil];

9
Примітка з документації: Не слід викликати метод перезавантаження даних посеред анімаційних блоків, де елементи вставляються або видаляються. Вставки та видалення автоматично призводять до належного оновлення даних таблиці.
Рафаель Олівейра

я думаю, це повинна бути правильна відповідь. тому що це спрацювало на мене. у мене є лише 1 розділ, і це працює, що не правильна відповідь.
Mahesh Agrawal

Не працює, якщо ви також вставляєте. Замінить сортування анімації.
Андрес Канелла

3
Варто зазначити, що для отримання анімації вам не потрібен self.collectionView performBatchUpdatesдзвінок, обгорнутий навколо reloadSections. Насправді performBatchUpdatesдзвінок може спричинити випадкові проблеми мерехтіння / зміни розміру комірки в деяких випадках.
Paul Popiel

1
Або просто [self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]]; reloadSectionsу поданні колекції або у вигляді таблиці це робитиме за допомогою анімації.
bauerMusic

67

Це те, що я зробив, щоб оживити перезавантаження ВСІХ РОЗДІЛІВ:

[self.collectionView reloadSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, self.collectionView.numberOfSections)]];

Стрімкий 3

let range = Range(uncheckedBounds: (0, collectionView.numberOfSections))
let indexSet = IndexSet(integersIn: range)
collectionView.reloadSections(indexSet)


3

Перезавантаження всього перегляду колекції всередині performBatchUpdates:completion:блоку робить для мене симпатичну анімацію на симуляторі iOS 9. Якщо у вас є конкретний варіант, який UICollectionViewCellви хочете видалити, або якщо у вас є його шлях до індексу, ви можете зателефонувати deleteItemsAtIndexPaths:в цей блок. Використовуючи deleteItemsAtIndexPaths:, він робить плавну і приємну анімацію.

UICollectionViewCell* cellToDelete = /* ... */;
NSIndexPath* indexPathToDelete = /* ... */;

[self.collectionView performBatchUpdates:^{
    [self.collectionView deleteItemsAtIndexPaths:@[[self.collectionView indexPathForCell:cell]]];
    // or...
    [self.collectionView deleteItemsAtIndexPaths:@[indexPath]];
} completion:nil];

1
Просто хочу згадати річ, яка вирішила проблему збою в моєму випадку, оновіть джерело даних (тобто кількість розділів / елементів) перед тим, як викликати perforUpdates у поданні колекції.
ViruMax

Анімація з інших операцій; є, і ніколи не був ПІД БУДЬ-ЯКИМИ ОБСТАВИНАМИ анімацією для reloadData. insertItems вставляє у порядку зростання та виконується ПІСЛЯ оновлення; deleteItems - це навпаки.
Джеймс Буш,

1

У довідковому тексті сказано:

Викличте цей метод, щоб перезавантажити всі елементи у поданні колекції. Це призводить до того, що подання колекції відкидає всі видимі на даний момент елементи та відображає їх повторно. Для ефективності подання колекції відображає лише ті клітинки та додаткові види, які видно. Якщо дані колекції зменшуються в результаті перезавантаження, подання колекції відповідно коригує зміщення прокрутки. Не слід викликати цей метод посеред анімаційних блоків, де елементи вставляються або видаляються. Вставки та видалення автоматично призводять до належного оновлення даних таблиці.

Я думаю, що ключовою частиною є "змушує подання колекції відкидати будь-які видимі на даний момент елементи". Як це буде оживляти рух відкинутих предметів?


Точно, це не так. reloadData - подвійна робота без анімації; це спочатку операція видалення, а потім операція вставки.
Джеймс Буш,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.