views:

1592

answers:

2

I was hitting my head over this one, and google was turning up nothing. I eventually worked it out and thought I'd write it up here for the sake of the next person.

You have a UITableView with multiple sections. Each section is homogeneous, but the table overall is heterogeneous. So you might want to allow re-ordering of rows within a section, but not across sections. Maybe you only even want want one section to be reorderable at all (that was my case).

If you're looking, as I was, at the UITableViewDataSource delegate you won't find a notification for when it is about to let you move a row between sections. You get one when it starts moving a row (which is fine) and one when it's already moved it and you get a chance to sync with your internal stuff. Not helpful.

So how can you prevent re-orders between sections?

I'll post what I did as a separate answer, leaving it open for someone else to post an even better answer!

+2  A: 

Simple enough, really.

The UITableViewDelegate has the method:


tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath:

This gets called while the user is hovering over a potential drop point. You get a chance to say, "no! don't drop it there! Drop it over here instead". You can return a different index path to the proposed one.

All I did was check if the section indices match. If they do then great, return the proposed path. if not, return the source path. This also nicely prevents the rows in other sections even moving out of the way as you drag - and the dragged row will snap back to it's original position of you try to move it to another section.


- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
{
    if( sourceIndexPath.section != proposedDestinationIndexPath.section )
    {
        return sourceIndexPath;
    }
    else
    {
        return proposedDestinationIndexPath;
    }
}
Phil Nash
+7  A: 

This implementation will prevent re-ordering outside of the original section like Phil's answer, but it will also snap the record to the first or last row of the section, depending on where the drag went, instead of where it started.

- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
{
  if (sourceIndexPath.section != proposedDestinationIndexPath.section) {
    NSInteger row = 0;
    if (sourceIndexPath.section < proposedDestinationIndexPath.section) {
      row = [self tableView:tableView numberOfRowsInSection:sourceIndexPath.section] - 1;
    }
    return [NSIndexPath indexPathForRow:row inSection:sourceIndexPath.section];     
  }

  return proposedDestinationIndexPath;
}
Jason Harwig
Thanks Jason. I can see that that could be useful too
Phil Nash