Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UICollectionView reorder animation

I am making a collection view with all basic stuff, like default FlowLayout, unique section.
Assuming I'm correctly using collectionView:CellForItemAtIndexPath: and all the other dataSource protocols

I have mainData, which is an array of dictionnaries (the original data), mainDataReferenceOrdered, mainDataNameOrdered and mainDataQuantiteOrdered are other arrays containing the same data as mainData (same elements pointed).
dataToDisplay is the controller's current array pointer to ordered data.

When reordering, I just change data in collection view batch, like this:

[itemCollectionControl.collectionView performBatchUpdates:^{
        dataToDisplay = mainDataReferenceOrdered; //or any other ordered array
        [itemCollectionControl.collectionView reloadSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, itemCollectionControl.collectionView.numberOfSections)]];
    } completion:^(BOOL finished) {}];

But the collection fades all cells, even if they are already visible, or at the right place.

I read the Apple documentation on UICollectionView, but I don't know what I missed. I also read other threads about that, but still looking for how I must do.

What do the batch looks to know which animation to apply on cells ?


My solution

This is the final code I use, certainly the closest of iOS programming guidelines I guess.

[itemCollectionControl.collectionView performBatchUpdates:^{
    NSArray *oldOrder = dataToDisplay;
    dataToDisplay = mainDataNBContainersOrdered;
    for (NSInteger i = 0; i < oldOrder.count; i++) {
        NSIndexPath *fromIndexPath = [NSIndexPath indexPathForRow:i inSection:0];
        NSInteger j = [dataToDisplay indexOfObject:oldOrder[i]];
        NSIndexPath *toIndexPath = [NSIndexPath indexPathForRow:j inSection:0];
        [itemCollectionControl.collectionView moveItemAtIndexPath:fromIndexPath toIndexPath:toIndexPath];
    }
} completion:^(BOOL finished) {
    if (finished) {
        [itemCollectionControl.collectionView reloadData];
    }
}];

I simply browse all old ordered items, check their new position, and apply it with -[UICollectionView moveItemAtIndexPath:toIndexPath:]
There's still some duplicated cells glitches, but it looks fine on iOS7 (not on iOS6). The completion might be useless on iOS7, I force the right order at the end on the iOS6 shuffling.

Edit

I think I found a solution, but I'm no longer able to test on that project. Maybe adding just 2 lines of code should fix this awful glitch.

before any call of -[UICollectionView moveItemAtIndexPath:toIndexPath:], call -[UICollectionView beginUpdates], and finally after all moves -[UICollectionView endUpdates].

If anyone able to test it found that it works, please tell me.

like image 514
Crazyrems Avatar asked Oct 22 '13 17:10

Crazyrems


1 Answers

The collection view doesn't know the identity of the items in your data model, so it has no way of knowing that they've moved. So you've got to explicitly tell the collection view where each cell moves to inside the batch update using moveItemAtIndexPath:toIndexPath:. You can calculate this yourself by looping over items in the from array and looking up their positions in the to array. Something like this (typed from memory, so sorry about any typos):

[itemCollectionControl.collectionView performBatchUpdates:^{
    for (NSInteger i = 0; i < mainDataReferenceOrdered.count; i++) {
        NSIndexPath *fromIndexPath = [NSIndexPath indexPathForRow:i inSection:0];
        NSInteger j = [mainDataNameOrdered indexOfObject:mainDataReferenceOrdered[i]];
        NSIndexPath *toIndexPath = [NSIndexPath indexPathForRow:j inSection:0];
        [itemCollectionControl.collectionView moveItemAtIndexPath:fromIndexPath toIndexPath:toIndexPath];
    }
} completion:^(BOOL finished) {}];

If you've got a lot (multiple thousands) of items, you might want to consider using sets for faster lookups.

A more generally applicable approach is to use something like TLIndexPathTools that can calculate the batch updates for you. Take a look at the Shuffle sample project.

like image 79
Timothy Moose Avatar answered Nov 11 '22 02:11

Timothy Moose