Custom animation for changing height of UITableViewCell

ios, uitableview, uiview, uiviewanimation

Solution

I think you should not use `beginUpdate`/`endUpdates` methods and perform animations manually before calling `reloadData`. The final state of cells (after animation) are defined with datasource. Here's an example of animation in `tableView:didSelectRowAtIndexPath:`

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    _selectedIndexPath = indexPath;

    [UIView animateWithDuration:1 animations:^{
        // move down cells which are below selected one
        for (UITableViewCell *cell in tableView.visibleCells) {
            NSIndexPath *cellIndexPath = [tableView indexPathForCell:cell];

            if (cellIndexPath.row > indexPath.row) {
                CGRect frame = cell.frame;
                frame.origin.y += kTargetHeight - tableView.rowHeight;
                cell.frame = frame;
            }
        }
        // expand selected cell
        UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];

        CGRect frame = cell.frame;
        frame.size.height = kTargetHeight;
        cell.frame = frame;
    } completion:^(BOOL finished) {
        [tableView reloadData];  // commit final state
    }];
}

The final state of selected cell:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if ([indexPath isEqual:_selectedIndexPath]) {
        return kTargetHeight;
    }

    return tableView.rowHeight;
}

Problem

I want to make animation of changing UITableViewCell height with UIView animation (in future with spring animation). So I have: ``` - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = (UITableViewCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; cell.backgroundColor = [UIColor greenColor]; } UILabel *viewLabel = [[UILabel alloc] initWithFrame:CGRectMake(10.0f, 10.0f, [[UIScreen mainScreen] bounds].size.width, 40.0f)]; viewLabel.text = @"Test"; viewLabel.backgroundColor = [UIColor clearColor]; [cell.contentView addSubview:viewLabel]; return cell; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView beginUpdates]; [self animateCell:indexPath andTableView:tableView]; [tableView endUpdates]; } - (void)animateCell:(NSIndexPath*)indexPath andTableView:(UITableView*)tableView { [UIView animateWithDuration:1.0f animations: ^ { UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; CGRect rect = cell.frame; rect.size.height = 90.0f; cell.frame = rect; NSLog(@"%f", cell.frame.size.height); }]; } ``` But it does not work. But if I`m adding: ``` - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { if ([indexPath isEqual:[tableView indexPathForSelectedRow]]) { return 90.0f; } return 40.0f; } ``` I see that cell is changing its height and animation is applied to custom cell that is created in animateCell method

Original source