Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UITableView Scrolls to Top on Cell Refresh

I have a UITableView with a cell that is dynamically sized to fit a UITextView inside it. Whenever a key is typed, the cell checks to see if the calculated height has increased, as with a newline, so it can tell the table the the cell's height needs to be recalculated. I do that with this code.

- (void) createNoteCellViewDidUpdate: (CreateNoteCell*) cell {

    CGFloat newHeight = [self tableView:self.tableView heightForRowAtIndexPath:CreateNoteCellIndexPath];
    if (newHeight != CGRectGetHeight(cell.contentView.frame)) {
        [self.tableView beginUpdates];
        [self.tableView endUpdates]; // <- HERE IS WHERE THE CONTENT OFFSET CHANGES
    }
}

The resize and table bounds are as expected. But instead of just animating the change in height, it also scrolls to the top. This can be seen here, when pressing the return key.

table scrolling on cell resize

By Key Value Observing, I've found out that the scroll view contentOffset is being set when the scroll view's contentSize changes. And that the contentSize changes many times when the endUpdates method is called. When it changes it goes from a normal height, to a rather large height, then back to a normal height. I wonder if it's going to top because of that. I don't know where to go from here.

like image 615
Jadar Avatar asked May 07 '15 18:05

Jadar


2 Answers

Here is my UITableView extension that works perfectly. In Swift 2.1. Based on the accepted answer.

extension UITableView
{
    func reloadDataAnimatedKeepingOffset()
    {
        let offset = contentOffset
        UIView.setAnimationsEnabled(false)
        beginUpdates()
        endUpdates()
        UIView.setAnimationsEnabled(true)
        layoutIfNeeded()
        contentOffset = offset
    }
}
like image 164
Sunkas Avatar answered Nov 15 '22 22:11

Sunkas


Wow, Josh Gafni's answer helped a lot; he deserves an upvote. My solution is based off his. This still feels like a hack, so if anyone still has a better way to do this, I'm still very interested to hear it.

First I save the content offset, then I start the update.

CGPoint offset = self.tableView.contentOffset;
[self.tableView beginUpdates];
[self.tableView endUpdates];

This animates the cell's height change and adjusts all the frames to suit the constraints.

Next I remove all animations from the tableView's layer, so the animation to the top stops. Then I reset the contentOffst to what it was before.

[self.tableView.layer removeAllAnimations];
[self.tableView setContentOffset:offset animated:NO];

Finally, I let the tableView handle the animated scroll down so the bottom of the cell is right above the keyboard.

[self.tableView scrollToRowAtIndexPath:CreateNoteCellIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];

And voila, it works pretty well.

fixed cell resize

like image 39
Jadar Avatar answered Nov 15 '22 21:11

Jadar