I'm having a problem in animating the addition or removal of a row in a UITableView which has a different height than other rows.
The following gifs demonstrats the issue with rows of the default height (44pts) and an larger row (100pts) being inserted and removed. The one on the left is a screen recording from the simulator (the new cell ending up covering row five is a different issue) and the one on the right is a mockup of what it should do.
In my case, I have a bunch of rows, each 60pts in height. When a button in the cell is tapped, an "edit" cell will slide out from underneath, pushing lower cells down. This edit cell is 180pts high. When I call insertRowsAtIndexPaths:withRowAnimation:
or deleteRowsAtIndexPaths:withRowAnimation:
, the animation assumes the wrong height of 60pts, instead of the 180pts it should be
This means that in the case of UITableViewRowAnimationTop
the new cell appears at -60pts from the position it will end up at, and slides down to its new position; about a third of the animation it should be doing. Meanwhile, the row below animates smoothly from its starting position to 180pts downward, exactly as it should.
Has anyone worked out an actual solution to this? some way to tell the new row what hight it's supposed to be for the animation?
Below is the code I am using to hide and show the edit row. I'm using a TLSwipeForOptionsCell
to trigger the edit, but it's easily replicated using for example tableView:didSelectRowAtIndexPath:
-(void)hideEditFields{
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:@[[NSIndexPath indexPathForItem:editFormVisibleForRow+1 inSection:0]] withRowAnimation:UITableViewRowAnimationTop];
editFormVisibleForRow = -1;
[self.tableView endUpdates];
}
-(void)cellDidSelectMore:(TLSwipeForOptionsCell *)cell{
NSIndexPath* indexPath = [self.tableView indexPathForCell:cell];
// do nothing if this is the currently selected row
if(editFormVisibleForRow != indexPath.row){
if(editFormVisibleForRow >= 0){
[self hideEditFields];
// update the index path, as the cell positions (may) have changed
indexPath = [self.tableView indexPathForCell:cell];
}
[self.tableView beginUpdates];
editFormVisibleForRow = indexPath.row;
[self.tableView insertRowsAtIndexPaths:@[
[NSIndexPath indexPathForItem:editFormVisibleForRow+1 inSection:0]
] withRowAnimation:UITableViewRowAnimationTop];
[self.tableView endUpdates];
}
}
-(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return _dataSource.count + (editFormVisibleForRow >= 0 ? 1 : 0);
}
-(CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
int row = indexPath.row;
if(editFormVisibleForRow >= 0 && row > editFormVisibleForRow && row <= editFormVisibleForRow + 1){
return 180.0f;
}
else return 60.0;
}
Poking around a bit, it seems like this is a common issue with no clear answer. Most of the similar questions I've found here on SO are unanswered or offer workarounds specific to the asker's situation. (examples: Problem with RowAnimation, Custom UITableViewCell height yields improper animation, UITableView animation glitch when deleting and inserting cells with varying heights).
Also, instead of trying to make one triple-sized edit row, I tried making three smaller rows and animating them, but this was not suitable because they all appeared at once. I also tried animating them one after the other but the easing made it look odd, with an obvious 3-step animation occurring, instead of the whole edit view sliding out of view in one motion.
Edit: I've just noticed that if I call reloadRowsAtIndexPaths:withRowAnimation: UITableViewRowAnimationNone
for the row above the one I'm trying to animate, it changes the behaviour of the animation; namely the animation assumes the height is 0pts, as demonstrated in the following animation. It's closer to what I want, but still not right, as the animation speed is wrong and it leaves a gap (in my app this means the background
colour pokes through)