Auto Layout constraint breaks when condition changes in table view cell

Viewed 447

In my tableView Cell, I have an array of strings from API which I uses to determine the height of a stackview based on the amount of array elements. The array can have 3, 4 or X number of elements.

var pollDataInPollCell: PollModel? {
        didSet{
            if let pollOptions = pollDataInPollCell?.poll_detail{
                // pollOptions = ["A", "B"] or ["A", "XS", "XSMAX"]

           optionBtnStackView.heightAnchor.constraint(equalToConstant: CGFloat(30 * pollOptions.count).isActive = true
}
var optionBtnStackView: UIStackView = {
   let sv = UIStackView()
    sv.axis = .vertical
    sv.distribution = .fillEqually
    return sv
}()

Everything works great at launch. The stackView height for each row looks perfect and there is no constraint breaking. However, if I scroll up and down the tableView, my stackView height isn't the same anymore and I believe it is due to tableView dequeueReusableCell. My question is if it is possible to reset my stackView height in didSet so that it can render new height. I have tried this in didSet

optionBtnStackView.heightAnchor.constraint(equalToConstant: 0).isActive = true
optionBtnStackView.heightAnchor.constraint(equalToConstant: CGFloat(30 * pollOptions.count).isActive = true

or

optionBtnStackView.heightAnchor.constraint(equalToConstant: CGFloat(30 * pollOptions.count).isActive = false
optionBtnStackView.heightAnchor.constraint(equalToConstant: CGFloat(30 * pollOptions.count).isActive = true

but both don't solve my problem. Any suggestions? Thank you so much.

1 Answers

I would assume that you are just adding new constraints to the old ones, and then they just collide.

This line:

optionBtnStackView.heightAnchor.constraint(equalToConstant: CGFloat(30 * pollOptions.count)).isActive = true

creates and activates a new constraint. If you call the same line again with different data, a new constraint is added with a different height, and then they collide.

Solution should be pretty easy and simple. First create a property and keep a reference to a single one constraint. Then, when setting data, just update the constant, and do not create a new constraint.

E.g., something like:

fileprivate var stackHeightConstraint: NSLayoutConstraint?

var pollDataInPollCell: PollModel? {
    didSet {
        if let pollOptions = pollDataInPollCell?.poll_detail {
            // lazily initialized heightConstraint:
            if stackHeightConstraint == nil {
                // this creates the constraint and keeps a reference to it
                stackHeightConstraint = optionBtnStackView.heightAnchor.constraint(equalToConstant: CGFloat(30 * pollOptions.count))
                // and we can activate it properly
                stackHeightConstraint?.isActive = true
            } else {
                // here the stackHeightConstraint is initialized, so just set the constant
                stackHeightConstraint?.constant = CGFloat(30 * pollOptions.count)
            }
        }
    }
}
Related