Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In an iOS table view, how should a row be moved to a new section?

I have a table view with two rows in one section, i.e

---
Row A
Row B

If I want to animate row 1 into a new section, i.e. the end result being:

---
Row B
---
Row A

how should this be achieved? What I have tried already is:

[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:@[[NSIndexPath indexPathForRow: 0 inSection: 0]] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView insertSections:[NSIndexSet indexSetWithIndex: 1] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];

However, in iOS 8 at least, the row animates out but then the new section is un-rendered (i.e. white, no bottom row border) until some time after when something triggers a redraw and it comes back.

[self.tableView beginUpdates];
[self.tableView moveRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] toIndexPath:[NSIndexPath indexPathForRow:0 inSection:1]];
[self.tableView endUpdates];

Which raises an exception:

Invalid update: invalid number of sections. The number of sections contained in the table view after the update (2) must be equal to the number of sections contained in the table view before the update (1), plus or minus the number of sections inserted or deleted (0 inserted, 0 deleted).

And:

[self.tableView beginUpdates];
[self.tableView insertSections:[NSIndexSet indexSetWithIndex: 1] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView moveRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] toIndexPath:[NSIndexPath indexPathForRow:0 inSection:1]];
[self.tableView endUpdates];

Which raises the exception:

cannot move a row into a newly inserted section (1) 

Should I just not animate at all and reload the whole table?

like image 585
Nick Avatar asked Oct 21 '22 00:10

Nick


1 Answers

You'll need to perform this in two steps.

First you'll need to add the section; you need to tell your data source to account for the new section. For a simple example like yours, you can just set a variable:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    if(hasTwoSections)
        return 2;

    return 1;
}

Then where you want to trigger the animation, call:

hasTwoSections = true;  // this needs to be set before endUpdates
[self.tableView beginUpdates];
[self.tableView insertSections:[NSIndexSet indexSetWithIndex: 1] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView endUpdates];

At this point, the tableView will call the data source methods to update the table based on your changes.

Once the section has been added, you can move the row to it in another update block:

[self.tableView beginUpdates];
[self.tableView moveRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] toIndexPath:[NSIndexPath indexPathForRow:0 inSection:1]];
[self.tableView endUpdates];

Obviously you'll need to update what numberOfRowsInSection returns to account for the change.

Although it's two steps, it will look like it's happening all at once.

like image 82
spongessuck Avatar answered Oct 22 '22 14:10

spongessuck