0

I currently am working with a uitableview that holds mostly standard size cells at 44pts. However, there are a couple that are larger, about 160pts.

In this instance, there are 2 rows at 44pts height, with the larger 160pts row being inserted below, at index 2 in the section.

Removal call:

- (void)removeRowInSection:(TableViewSection *)section atIndex:(NSUInteger)index {
    NSUInteger sectionIndex = [self.sections indexOfObject:section];

    NSIndexPath *removalPath = [NSIndexPath indexPathForRow:index inSection:sectionIndex];

    [self.tableView beginUpdates];
    [self.tableView deleteRowsAtIndexPaths:@[removalPath] withRowAnimation:UITableViewRowAnimationAutomatic];
    [self.tableView endUpdates];
}

Delegate call:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    TableViewSection *section = [self sectionAtIndex:indexPath.section];

    return [section heightForRowAtIndex:indexPath.row];
}

section call:

- (NSInteger)heightForRowAtIndex:(NSInteger)index {
    StandardCell *cell = (StandardCell *)[self.list objectAtIndex:index];

    return cell.height;
}

cell call:

- (CGFloat)height {
    return 160;
}

What has me confused is when I remove the larger rows from the table, they start to animate, moving underneath the row above. But when they get to a certain point, about a 1/4 of the way through the animation, they disappear instead of finishing the animation.

It seems like the table animates the row with the notion that it's only 44pts, then once it's reached the point where 44pts are underneath the row above, it gets removed from the table. What detail have I overlooked that will give the table the correct notion to automatically animate the row removal?

Thanks for your help.

Update: I tried commenting out the height function above (which overrides the default that returns 44). This results in a proper animation with no skips. FWIW

user1869469
  • 491
  • 4
  • 13
  • I was unable to reproduce this. Could you share more details like a) more view controller code, b) what index paths exist and what are their heights, c) what batch updates are you making against what index paths with which animation option? – Timothy Moose Sep 04 '13 at 14:33
  • Thanks for the help. I added the only other code being executed, which is the removal call. It seems to work fine with any other row. – user1869469 Sep 04 '13 at 17:15
  • I don't see anything wrong with your code. If it helps, here's a link to [my sample project](https://dl.dropboxusercontent.com/u/2183704/Delete%20Tall%20Row.zip). The animation looks smooth to me. However, if there aren't enough rows below the cell being deleted, it may show through the bottom during animation. The fade animation style looks better IMO. – Timothy Moose Sep 04 '13 at 17:40
  • OK, now I reproduced it given your updated info. The key that a) the cell being deleted is the last cell and b) you're using top or bottom animation type. I think the simplest solution is to use fade animation type. – Timothy Moose Sep 04 '13 at 17:46
  • Is there any way to avoid using the fade animation type? There are certain circumstances when the last two (44pt, and 160pt) rows will be deleted together, meaning one will fade and one will slide upwards. And I'd rather not have them both fade. – user1869469 Sep 04 '13 at 17:48

1 Answers1

4

One way to solve this is to animate the row height down to 44 just before deleting:

//mark index paths being deleted and trigger `contentSize` update
self.indexPathsBeingDeleted = [NSMutableArray arrayWithArray:@[indexPath]];
[tableView beginUpdates];
[tableView endUpdates];

//delete row
[self.tableView deleteRowsAtIndexPaths:@[removalPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[tableView endUpdates];

And then in your heightForRowAtIndexPath:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if ([self.indexPathsBeingDeleted containsObject:indexPath]) {
        //return normal height if cell is being deleted
        [self.indexPathsBeingDeleted removeObject:indexPath];
        return 44;
    }
    if (<test for tall row>) {
        return 160;
    }
    return 44;
}

There's a little bit of bookkeeping going on to keep track of index paths being deleted. There are probably cleaner ways to do this. This is just the first thing that came to mind. Here's a working sample project.

Timothy Moose
  • 9,895
  • 3
  • 33
  • 44
  • Thanks for the idea. Although, I'm not too fond of workarounds, I'll see how this works out for me. There must be some other trick to it though, because I've seen the ios7 reminders app do the same thing with an in-cell date picker... maybe next week the api will change. – user1869469 Sep 04 '13 at 23:18
  • I'd guess the date picker is an expanding cell rather than two separate cells. And the hiding and showing of the date cell looks like a fade animation to me. My test project doesn't fare any better in [redacted]. – Timothy Moose Sep 04 '13 at 23:32
  • I worked out a pretty simple way to implement your idea of changing the row height to 0 in my project. Basically I just have the tall row in the table all the time, except when I need to show it, instead of inserting it, I change the height appropriately and update the table. Worked like a charm and looks great! Thanks again! – user1869469 Sep 04 '13 at 23:48