2

I've been looking over NSTableView's moveRowAtIndex:toIndex method for animating rows in a table. It's not really helpful for sorting though from what I can tell. My interpretation of how it works is, if I want to move row 0 to row 4, then the rows in between are handled appropriately. However, if I have a table view with an array backing it, and then I sort the array, I want the table view to animate from the old state to the new state. I don't know which items were the ones that moved vs the ones that shift to accommodate the moved ones.

Example:

[A,B,C,D] --> [B,C,D,A]

I know that row 0 moved to row 3 so I would say [tableView moveRowAtIndex:0 toIndex:3]. But if I apply some custom sort operation to [A,B,C,D] to make it look like [B,C,D,A], I don't actually know that row 0 moved to row 3 rather than rows 1,2, and 3 moving to rows 0,1, and 2. I would think that I should just be able to specify all of the movements (row 0 moved to row 4, row 1 moved to row 0, etc.) but the animation doesn't look correct when I try that.

Is there a better way to do this?

Edit: I found this site, which seems to do what I want but seems like a bit much for something that should be simple (at least I think it should be simple)

Andriy
  • 2,767
  • 2
  • 21
  • 29
JPC
  • 8,096
  • 22
  • 77
  • 110

1 Answers1

6

The documentation for moveRowAtIndex:toIndex: says, "Changes happen incrementally as they are sent to the table".

The significance of 'incrementally' can be best illustrated with the transformation from ABCDE to ECDAB.

If you just consider the initial and final indexes, it looks like:

E: 4->0
C: 2->1
D: 3->2
A: 0->3
B: 1->4

However, when performing the changes incrementally the 'initial' indexes can jump around as you transform your array:

E: 4->0 (array is now EABCD)
C: 3->1 (array is now ECABD)
D: 4->2 (array is now ECDAB)
A: 3->3 (array unchanged)
B: 4->4 (array unchanged)

Basically, you need to tell the NSTableView, step-by-step, which rows need to be moved in order to arrive at an array identical to your sorted array.

Here's a very simple implementation that takes an arbitrarily sorted array and 'replays' the moves required to transform the original array into the sorted array:

// 'backing' is an NSMutableArray used by your data-source
NSArray* sorted = [backing sortedHowYouIntend];

[sorted enumerateObjectsUsingBlock:^(id obj, NSUInteger insertionPoint, BOOL *stop) {

  NSUInteger deletionPoint = [backing indexOfObject:obj];

  // Don't bother if there's no actual move taking place
  if (insertionPoint == deletionPoint) return;

  // 'replay' this particular move on our backing array
  [backing removeObjectAtIndex:deletionPoint];
  [backing insertObject:obj atIndex:insertionPoint];

  // Now we tell the tableview to move the row
  [tableView moveRowAtIndex:deletionPoint toIndex:insertionPoint];
}];
Trevor Squires
  • 531
  • 4
  • 7
  • This looks pretty similar to what I was trying to come up with. Although I haven't tested this version, I think the underlying problem is that in order for the animation to be smooth, I have to figure out what the minimum amount of moveRowAtIndex calls will transform the unsorted array into the sorted array. – JPC Nov 30 '11 at 17:40
  • The 'incremental' issue is only related to mutating the NSTableView's internal housekeeping and should have no bearing on animation smoothness. As long as you bracket your changes with beginUpdates and endUpdates, it will always perform the minimum number of row moves, probably more moves than you expect. For example ABCDE -> EABCD is just one 'move' but the position of *all* of the rows will be affected (assuming all are visible on screen), so all of the rows will animate. – Trevor Squires Nov 30 '11 at 18:16
  • Hmm. I'll look into it some more but at least from my observations I've been seeing some jerky animations – JPC Nov 30 '11 at 23:35
  • After your enumeration completes, you probably want to assign `backing = sorted` (I'm assuming ARC for simplicity). – Richard Dec 04 '13 at 17:16
  • 1
    This looks great. I'm using it as a category on NSTableView. Gist here: https://gist.github.com/zpasternack/a8724c31858133873215 – zpasternack Aug 18 '14 at 00:01