3

I have a very frustrating issue. I have an app with a UITableView. When I am removing a cell from the table view, it is removed from the data model and then I call the following:

-(void)removeItem:(NSIndexPath *)indexPath {
    [self.tableView beginUpdates];

    [self.tableView deleteRowsAtIndexPaths:@[indexPath]
                      withRowAnimation:UITableViewRowAnimationRight];
    [self.tableView endUpdates];
}

My problem is, I've tried it like I do above, and I've tried without using animateWithDuration. I've even tried with a CATransaction, but however I do it, the animation doesn't happen.

I've got slow animations on in my Simulator and when I remove an item from the list, it removes correctly, but without animation. It just disappears and leaves a blank space for a moment before the table view data is reloaded.

I've search all over SO and Google and I can't seem to find an answer. Any ideas?

Does it perhaps have to do with the fact that I'm removing the object from the data model before calling the function above?

Edit: Removed the Animation Block as it is incorrect

Daniel Retief Fourie
  • 626
  • 2
  • 10
  • 20
  • Try removing it all out of the `animateWithDuration:animations:` block. The table view handles the animations on it's own, you don't need to do anything else. – IluTov Aug 20 '13 at 13:26
  • 1
    Show your `commitEditingStyle:` method please – Valentin Shamardin Aug 20 '13 at 13:27
  • Thanks everyone, but like I said in the question, I tried without the animateWithDuration:animations: as well, and it doesn't resolve the problem. @Valentin: Will show soon. – Daniel Retief Fourie Aug 20 '13 at 13:46
  • I'm fairly new to this part of the code and iOS in general. I see that we are not implementing the commitEditingStyle: method. The actual removal from the data model happens in a removal block inside a RESTKit call if that makes a difference. – Daniel Retief Fourie Aug 20 '13 at 13:49
  • 1
    I would suggest editing the animation block out of your question because it's just plain wrong. Otherwise, the code you've shared looks correct. But you haven't really shared much. I'm wondering what else you're doing that could interrupt the animation. You said "before the table view data is reloaded". I don't know what you mean by that. You aren't calling `reloadData` are you because that would likely break animation? – Timothy Moose Aug 21 '13 at 00:09
  • Thank Timothy, I'll edit out the animation block. What I mean by table view data is reloaded, is that the cell is removed leaving a blank spot immediately, right before the other items lower down slide up to fill the empty space. – Daniel Retief Fourie Aug 21 '13 at 06:27

4 Answers4

7

According to THIS you don't need to use the animateWithDuration:animations: at all.

Just try it like this

-(void)removeItem:(NSIndexPath *)indexPath {
    [self.tableView beginUpdates];
    [self.tableView deleteRowsAtIndexPaths:@[indexPath]
                  withRowAnimation:UITableViewRowAnimationRight];
    [self.tableView endUpdates];
}
Community
  • 1
  • 1
IluTov
  • 6,807
  • 6
  • 41
  • 103
3

Okay, I don't know if it's just bad manners, but I feel I'm going to answer my own question here.

First, thanks for all the other answers, you were all correct of course, but none of the answers solved my problem.

It turns out that there is another area in the code that does a different check then calls one of the tableView delegate methods, that seems to cancel the animation.

So the answer is as follows:

When you're row is removing but the animations aren't working, make sure that you are not calling didSelectRowAtIndexPath:indexPath before the animation starts. This will cancel the animations.


If you're NOT having that problem, here's some really typical code for expanding, two lines in the example:

Note that facebookRowsExpanded is a class variable you must have:

if ( [theCommand isEqualToString:@"fbexpander"] )
{
NSLog(@"expander button......");
[tableView deselectRowAtIndexPath:indexPath animated:NO];

NSArray *deleteIndexPaths;
NSArray *insertIndexPaths;

facebookRowsExpanded = !facebookRowsExpanded;
// you must do that BEFORE, not AFTER the animation:

if ( !facebookRowsExpanded ) // ie, it was just true, is now false
    {
    deleteIndexPaths = [NSArray arrayWithObjects:
            [NSIndexPath indexPathForRow:2 inSection:0],
            [NSIndexPath indexPathForRow:3 inSection:0],
             nil];
    [tableView beginUpdates];
    [tableView
        deleteRowsAtIndexPaths:deleteIndexPaths
        withRowAnimation: UITableViewRowAnimationMiddle];
    [tableView endUpdates];
    }
else
    {
    insertIndexPaths = [NSArray arrayWithObjects:
            [NSIndexPath indexPathForRow:2 inSection:0],
            [NSIndexPath indexPathForRow:3 inSection:0],
             nil];
    [tableView beginUpdates];
    [tableView
        insertRowsAtIndexPaths:insertIndexPaths
        withRowAnimation: UITableViewRowAnimationMiddle];
    [tableView endUpdates];
    }

// DO NOT do this at the end: [_superTableView reloadData];
return;
}

NOTE: your code for numberOfRowsInSection must use facebookRowsExpanded

(it will be something like "if facebookRowsExpanded return 7, else return 5")

NOTE: your code for cellForRowAtIndexPath must use facebookRowsExpanded.

(it has to return the correct row, depending on whether or not you are expanded.)

Fattie
  • 27,874
  • 70
  • 431
  • 719
Daniel Retief Fourie
  • 626
  • 2
  • 10
  • 20
  • 2
    I had the same problem today, and in my case it turned out that calling the reloadData method cancels out the animation. By deleting the reloadData method brought back the animation, which I see you also write in a comment at the end of your code. –  Apr 16 '14 at 07:15
2

First, you don't need to animate the change yourself.

Second, I think you need to make the changes to the datasource between the begin and end updates.

Your method should look something like this:

-(void)removeItemAtIndexPath:(NSIndexPath *)indexPath{

    [self.tableView beginUpdates];

    // I am assuming that you're just using a plain NSMutableArray to drive the data on the table.

    // Delete the object from the datasource.
    [self.dataArray removeObjectAtIndex:indexPath.row];

    // Tell the table what has changed.
    [self.tableView deleteRowsAtIndexPaths:@[indexPath]
                  withRowAnimation:UITableViewRowAnimationRight];

    [self.tableView endUpdates];
}
pckill
  • 3,709
  • 36
  • 48
Fogmeister
  • 76,236
  • 42
  • 207
  • 306
  • I will see if that is possible. The removal from the data model is complex and happens in a different place altogether, inside a block that is coupled to a call to RESTKit. I'll give it a shot and see if it is possible. I just don't know if that is the issue. Since the removal from the tableview works 100%, it just doesn't animate. – Daniel Retief Fourie Aug 20 '13 at 13:55
1
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade];
[self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];

indexPaths is an array of NSIndexPaths to be inserted or to be deleted in your table.

 NSarray *indexPaths = [[NSArray alloc] initWithObjects:
    [NSIndexPath indexPathForRow:0 inSection:0],
    [NSIndexPath indexPathForRow:1 inSection:0],
    [NSIndexPath indexPathForRow:2 inSection:0],
    nil];
Kunal Gupta
  • 2,984
  • 31
  • 34