UICollectionView animate data change

IosUicollectionview

Ios Problem Overview


In my Project I use UICollectionView to display a grid of icons.

The user is able to change the ordering by clicking a segmented control which calling a fetch from core data with different NSSortDescriptor.

The amount of data is always the same, just ending up in different sections / rows:

- (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];
}

The problem is that reloadData doesn't animate the change, UICollectionView just pops with the new data.

Should I keep track in which indexPath a cell was before and after change, and use [self.collectionView moveItemAtIndexPath: toIndexPath:] to perform the animation for the change or there is a better method ?

I didn't get much into subclassing collectionViews so any help will be great...

Thanks, Bill.

Ios Solutions


Solution 1 - Ios

Wrapping -reloadData in -performBatchUpdates: does not seem to cause a one-section collection view to animate.

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

However, this code works:

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

Solution 2 - Ios

reloadData doesn't animate, nor does it reliabably do so when put in a UIView animation block. It wants to be in a UICollecitonView performBatchUpdates block, so try something more like:

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

Solution 3 - Ios

This is what I did to animate reload of ALL SECTIONS:

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

Swift 3

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

Solution 4 - Ios

For Swift users, if your collectionview only has one section:

self.collectionView.performBatchUpdates({
                    let indexSet = IndexSet(integersIn: 0...0)
                    self.collectionView.reloadSections(indexSet)
                }, completion: nil)

As seen on https://stackoverflow.com/a/42001389/4455570

Solution 5 - Ios

Reloading the whole collection view inside a performBatchUpdates:completion: block does a glitchy animation for me on iOS 9 simulator. If you have a specific UICollectionViewCell you want do delete, or if you have it's index path, you could call deleteItemsAtIndexPaths: in that block. By using deleteItemsAtIndexPaths:, it does a smooth and nice animation.

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

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

Solution 6 - Ios

The help text says:

> Call this method to reload all of the items in the collection view. > This causes the collection view to discard any currently visible items > and redisplay them. For efficiency, the collection view only displays > those cells and supplementary views that are visible. If the > collection data shrinks as a result of the reload, the collection view > adjusts its scrolling offsets accordingly. You should not call this > method in the middle of animation blocks where items are being > inserted or deleted. Insertions and deletions automatically cause the > table’s data to be updated appropriately.

I think the key part is "causes the collection view to discard any currently visible items". How is it going to animate the movement of items it has discarded?

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionNimrod7View Question on Stackoverflow
Solution 1 - IospaulmelnikowView Answer on Stackoverflow
Solution 2 - IosStripesView Answer on Stackoverflow
Solution 3 - IosYariv NissimView Answer on Stackoverflow
Solution 4 - IosGabriel WamunyuView Answer on Stackoverflow
Solution 5 - IosnemesisView Answer on Stackoverflow
Solution 6 - IosVictor EngelView Answer on Stackoverflow