I have a UITableView that I fill with autosizing cells.
UITableView
setup is fairly simple:
tableView.estimatedRowHeight = 70
tableView.rowHeight = UITableViewAutomaticDimension
Exactly like Apple recommends here: https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/AutolayoutPG/WorkingwithSelf-SizingTableViewCells.html
To enable self-sizing table view cells, you must set the table view’s rowHeight property to UITableViewAutomaticDimension. You must also assign a value to the estimatedRowHeight property. As soon as both of these properties are set, the system uses Auto Layout to calculate the row’s actual height.
When configuring a cell I also disable/enable some constraints to achieve the needed look. That’s where things get interesting. Cell layout is not updated until the cell is reused. Literally. You can call layoutIfNeeded()
, setNeedsLayout()
, layoutSubviews()
or any other method there is, there is no way you will force the cell to update its layout.
All other aspects work pretty good: labels do change their text, you hide/unhide the views, but layout is stuck until the cell is reused.
Question: what causes it and how to avoid this behavior?
I had your problem too. Instead of remove
tableView.estimatedRowHeight = 70
I just added a layoutIfNeeded at the end of the cellForRow method, just before return the cell itself:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "identifier", for: indexPath) as? MyCustomCell
...
cell?.layoutIfNeeded()
return cell!
}
Result: the cell layout is perfect always, the first time and every after reuse.
Unfortunately, none of the provided answers/comments worked out for me. I always ended up with an initially incorrect layout. Only after reusing the cell, or calling reloadData()
(on the table view) it was displayed correctly.
The following was the only thing, that worked for me in the end. I'm not a big fan of such hacks, but after spending about half a day on this seemingly very simple layout issue, I just gave up and went with it. >.<
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
Alternatively you could also call reloadData
it in viewDidAppear
(without the DispatchQueue
hack), but then you can clearly see the "jump" when the layout jumps from "incorrect" to "correct".
Anyway, just wanted to share my experience and hope this helps someone else. Cheers!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With