Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UITableViewCell layout not updating until cell is reused

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?

like image 561
xinatanil Avatar asked Nov 10 '16 18:11

xinatanil


2 Answers

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.

like image 188
carmine Avatar answered Nov 14 '22 23:11

carmine


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!

like image 21
d4Rk Avatar answered Nov 14 '22 22:11

d4Rk