Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UITableView jumps up after begin/endUpdates when using UITableViewAutomaticDimension [duplicate]

The problem: When I'm at the bottom of the UITableView (and only when at the bottom) and tableView.beginUpdates()/tableView.endUpdates() is called, the UITableView jumps up a little bit. I don't want it to do this.

Set Up: I have a UITableView with UITableViewCells that will all be different sizes, and I'm using UITableViewAutomaticDimension to size the cells.

Example: When I'm at the bottom of the UITableView and I select a cell, which subsequently calls tableView.beginUpdates()/tableView.endUpdates(), the UITableView scrolls/jumps up just a bit.

Has anyone found a way to make it so there's no jumpiness after calling tableView.beginUpdates()/tableView.endUpdates() while at the end of the UITableView?

For the time being I'm calculating all my UITableViewCells manually, I'd rather not do this though because I'd like to take advantage of UITableViewAutomaticDimension.

Code:

Here's some code to display what goes on between tableView.beginUpdates()/tableView.endUpdates():

    tableView.beginUpdates()     cell!.setNeedsUpdateConstraints()     cell!.updateConstraintsIfNeeded()     cell!.setNeedsLayout()     cell!.layoutIfNeeded()     tableView.endUpdates() 

My viewWillAppear:

public override func viewWillAppear(animated: Bool) {     super.viewWillAppear(animated)      self.tableView.estimatedRowHeight = 150.0     self.tableView.rowHeight = UITableViewAutomaticDimension       self.tableView.reloadData()     //Bug in 8.0+ forces us to call three extra methods to get dynamic cell heights to work correctly...     self.tableView.setNeedsLayout()     self.tableView.layoutIfNeeded()     self.tableView.reloadData() } 

My heightForRow:

public override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {      return UITableViewAutomaticDimension  } 

Update: Removing cell!.setNeedsUpdateConstraints(), cell!.updateConstraintsIfNeeded(), cell!.setNeedsLayout(), and cell!.layoutIfNeeded() from tableView.beginUpdates()/tableView.endUpdates() appears to stop the jumping, but then my cells do not resize...

Edit: This only occurs when at the bottom of the UITableView.

like image 938
Sakiboy Avatar asked Nov 18 '15 20:11

Sakiboy


1 Answers

Actually I found a nice method to fix this.. It drove me crazy but look:

So you

  • Have a table with expandable content
  • Wanna animate a cell's constraints (height for example)
  • And therefore you call tableView.beginUpdates() and tableView.endUpdates()

And soo the table jumps..

As others have said before, it is because updating the tableView makes the tableView Scroll

The solution?

Let's assume your code looks like this:

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {         let cell = tableView.cellForRow(at: indexPath)         cell.heightConstraint = 100         UIView.animate(withDuration: 0.15, animations: {              self.view.layoutIfNeeded()             self.tableView.beginUpdates()             self.tableView.endUpdates()         }, completion: nil) } 

Then to fix the jumping issue you have to save the current tableView scroll position until the tableView.endUpdates() being called.

Like this:

var currentScrollPos : CGFloat?  override func scrollViewDidScroll(_ scrollView: UIScrollView) {         // Force the tableView to stay at scroll position until animation completes         if (currentScrollPos != nil){             tableView.setContentOffset(CGPoint(x: 0, y: currentScrollPos!), animated: false)         } } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {         let cell = tableView.cellForRow(at: indexPath)         cell.heightConstraint = 100         UIView.animate(withDuration: 0.15, animations: {              self.currentScrollPos = self.tableView.contentOffset.y              self.view.layoutIfNeeded()             self.tableView.beginUpdates()             self.tableView.endUpdates()              self.currentScrollPos = nil         }, completion: nil) } 
like image 170
Kárpáti András Avatar answered Sep 21 '22 05:09

Kárpáti András