2

I want to update the bottom cell in my UITableView, and scroll the view down all the way so that the entirety of the new cell is visible. (The cell's old content is about 50 pixels tall; the new content is about 100 pixels tall. And the table's content is much taller than its bounding view.) But when I do this:

tableView.beginUpdates()
tableView.reloadRows(at: [myIndexPath], with: .none)
tableView.endUpdates()
tableView.setContentOffset(
    CGPoint(x: 0, y: tableView.contentSize.height - tableView.bounds.size.height),
    animated: true)

then, instead, I get scrolled upwards to above the top of my tableView. The problem is that, the moment endUpdates is called, tableView.contentSize.height suddenly shrinks by a few hundred pixels, so that it's smaller than the bounding view. I don't understand why that is.

I've found that if I add a delay of about 500ms or longer around setContentOffset, then things work properly, but I don't want to have to use a delay.

DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(500)) {
    self.tableView.setContentOffset(CGPoint(x: 0, y: self.tableView.contentSize.height - self.tableView.bounds.size.height),
                                    animated: true)
}

I've tried using a CATransation, per https://stackoverflow.com/a/35228192/548862, but that's not having any effect on the problem.

I have a tableView estimatedHeightForRowAt method to estimate the row heights (from a set of constants), but I don't see how that could be messing me up.

What am I doing wrong?

Community
  • 1
  • 1
Brian Kendig
  • 2,452
  • 2
  • 26
  • 36
  • Why not use `scrollToRowAtIndexPath:atScrollPosition:animated:` instead? – crizzis Dec 19 '16 at 21:05
  • Thank you for the idea - I tried putting `tableView.scrollToRow(at: myIndexPath, at: .bottom, animated: true)` immediately after the `endUpdates` call, but that jumps to the top of the tableview and then scrolls down from there. Additionally, this gives me some weird effects such as one cell's contents scrolling at a different rate than the rest of the table, and both the old and new content appearing in the bottom cell until the scroll is finished. – Brian Kendig Dec 19 '16 at 21:21
  • Is there a chance `tableView:estimatedHeightForRowAt:` is underestimating the cell's actual height? If weird things happen during animations of self-sizing cells, that method is usually the prime suspect. – crizzis Dec 19 '16 at 21:53
  • Also, consider replacing`.bottom` with `.none`, which will try to scroll the view until the requested cell is fully visible, with minimum amount of movement. – crizzis Dec 19 '16 at 21:59
  • Is there any way I can get rid of `tableView:estimatedHeightForRowAt:`, at least temporarily even if there's a performance hit, to see whether it's responsible? I don't mind letting the OS calculate the actual sizes of the cells, but if I remove this method entirely then my cells all have minimal heights and are cut off. – Brian Kendig Dec 20 '16 at 01:19
  • Not that I know of (I understand that you are letting autolayout decide the cells' height). What you could do is you could back your table view with dummy data and make `tableView:estimatedHeightForRowAt:` return the exact, precalculated height for each cell. If the problem persists, then it might be another issue. – crizzis Dec 20 '16 at 09:44

0 Answers0