Search code examples
ios6uitableview

Redraw a table after animating it moving


I have an app that changes the contents of a table view cell when the user taps a button in that cell. If the cell is partially visible at the bottom of the screen, I have an animation move the table view up to display the entire cell (then move it back when done). On iOS 7, everything is fine. But on iOS 6, the shifted cell consists only of what was visible before the shift; anything that was 'hidden' behind the tab bar is blank white. I've tried calling [self.view setNeedsDisplay], and even [self.view performSelector: @selector(setNeedsDisplay) withObject: nil afterDelay: 0.5], but it still doesn't redraw correctly.

I overrode -drawRect: in the table view cell class, calling [super drawRect: rect] and set a breakpoint there, and that runs before the animation happens.

How can I get the redraw to take place after the animation?

In the custom UITableViewController:

- (void) shiftTable: (CGFloat) distance
{
    [UIView beginAnimations: @"TableShift" context: nil];
    [UIView setAnimationBeginsFromCurrentState: YES];
    [UIView setAnimationDuration: 0.35];
    self.view.frame = CGRectOffset(self.view.frame, 0, distance);
    [UIView commitAnimations];
}

Solution

  • I figured out the issue:

    Shifting the view via an animation like that doesn't reveal any more data. The line where it clipped the visible data is in the same position relative to the cell, and the cell is in the same position relative to the view. On iOS 7, where it draws the table view behind the translucent tab bar, the data is already there (but obscured), so when it shifts, it reveals that data. In iOS 6, the tab bar is not translucent, so the table view stops at the top edge of the tab bar. When the animation moves the view, it moves the clipped view up.

    The solution is to scroll the table view, rather than just move the view:

        CGRect cellRect = [self.tableView convertRect: cell.frame toView: self.tableView.superview];
        CGRect tableRect = self.tableView.frame;
        if (cellRect.origin.y < tableRect.origin.y)
        {
            [self.tableView scrollToRowAtIndexPath: cell.indexPath
                                  atScrollPosition: UITableViewScrollPositionTop animated: YES];
        }
        else if (cellRect.origin.y + cellRect.size.height >
                 tableRect.origin.y + tableRect.size.height)
        {
            [self.tableView scrollToRowAtIndexPath: cell.indexPath
                                  atScrollPosition: UITableViewScrollPositionBottom animated: YES];
        }