UITableView animate row reordering upon sort

I have a table that users can sort in two different ways. When users change between these two sorting modes, I want the re-sort to be animated. And while UITableView's methods provide animation help for inserting, deleting, and reloading rows, I don't see anything that lets me animate row movement.

Am I missing something?

Assuming I'm not, does anyone have any sample code on how to do this?

Thanks.

Answers


I know this is an older question, but I ran into the same issue and think I found a solution, so I thought I'd share in case anyone else finds their way here with the same question. I'm also not sure how great of a solution it is, but it seems to work for me.

My TableView gets its data from an array called _objects. In my method for sorting, I begin by creating another array which is an exact copy of the data array:

    NSArray *objectsBeforeSort = [NSArray arrayWithArray:_objects];

I then sort my data array, _objects, using sort descriptors that I had already created. After calling the appropriate sort method on my array, I use this to animate the table update:

[self.tableView beginUpdates];

for (int i = 0; i < _objects.count; i++)
{
    // newRow will get the new row of an object.  i is the old row.
    int newRow = [_objects indexOfObject:objectsBeforeSort[i]];
    [self.tableView moveRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0] toIndexPath:[NSIndexPath indexPathForRow:newRow inSection:0]];
}


[self.tableView endUpdates];

I haven't tested this code extensively yet, but it appears to give the desired result.


Have you tried using moveRowAtIndexPath:toIndexPath: inside a beginUpdates-endUpdates block? It seems to be what the developer docs are currently recommending. If that doesn't work on its own you could also try wrapping it in a [UIView animateWithDuration:animations:] block.

Link to the ADC documentation for UITableView: https://developer.apple.com/library/ios/#documentation/UIKit/Reference/UITableView_Class/Reference/Reference.html#//apple_ref/doc/c_ref/UITableView


The presented solutions has some draw-backs, which makes me question if animated sorting is desirable.

  • All values in the array is assumed to be unique. A list of numbers, where the same number occurs several times, would return the same index for each of the instance of this number.

  • Sorting is done into a new array. Memory requirements is doubled.

  • The algorithm is inefficient. For each value in the sorted array, the original array is scanned for the origin of the value.

  • Even with an efficient algorithm, who wants to see 10000 rows animate? Instantiating 10000 views, Even 500 views, would be undesirable.

That being said, if it had to be done, a better solution would be to create your own merge sort function, that sorts in place, or grab the sort implementation from the Swift repositories. Create a seperate class that tracks the movement of each index in the array. Finally only animate the visible rows plus the over-reach. The table view has this information.

This solution is more efficient, but the overhead of tracking the index movements is non-trivial, when the swift sort algorithm is so efficient. Allocating the required space, in the array, up front would mitigate it to some degree. Additionally it only works when the backing store is an array. It does not work if you do sorting through Core Data. I would probably only do the animation, if the table had less than a 1000 values.


Need Your Help

Is the copyright meta tag valid in HTML5?

html5 validation w3c

&lt;meta name="copyright" content="By Me" /&gt;

Is it possible to move a boost::optional?

c++ boost c++11 move-semantics boost-optional

I've been trying to define a defaulted move constructor in a class with a boost::optional member variable.