Recently I needed to update the contents of a
UICollectionView. Simple right? Just call
reloadData and be done with it.
However this results in poor UX because users don’t get the visual feedback of how items got reordered. Of course the solution is to animate insert/delete/move items in the
performBatchUpdates block, but how can we get from the old list of items to the new one?
Suppose we have an array of integers that we are currently displaying in the collection view. When a user taps on a button, we want to display a different list of integers, potentially including numbers that were present in the original list.
Luckily all of the animation is builtin; the only thing we need to do is tell the collection how to change. The order to accomplish this is to delete, then move, and finally insert.
Here is the high level of what we are going to do. Each step is encapsulated inside its own update block to make it more clear, as well as to ensure our data source is in sync with the internal collection view.
Step 1: Delete
One thing to note is that
UICollectionView only allows a single delete at any given index path inside a
performBatchUpdates block. For example, if we want to delete the first two elemnts, we can’t call delete at index path
0 twice like we could an array.
This means that we cannot simply iterate and delete as we go along, because deleting an element shifts every element after by one. Thus, the indices would be incorrect (bad) and we might call delete twice with the same index (worse!). To get around this, we can simply reverse the iteration order so that we start with the last element, as this does not change future indices that are iterated.
Step 2: Move
The goal of the second step is to move the existing items into the correct order in the new list. (This can be further optimized by creating a dictionary containing the mapping from item to index instead of performing a linear search every time.)
Step 3: Insert
Finally we compute and create index paths that correspond to the new items, assign the
newItems to our instance variable, and give the collection view the array of new indices to insert. (Again, a slight optimization is to compute the new index paths inside the
guard statement of the second step.)
Hopefully this shows that it doesn’t take a lot of additional work to create a much better UX with animation. A demo project is available here.