Crazyrems
Crazyrems

Reputation: 2601

Animate a layout constraint by changing its priority value

I have a label containing quite a lot of text. There's a toggle for collapsing and expanding the height of the label (here it's named "lire la suite") so it truncates the end of the text.

enter image description here

I have meticulously set the vertical content hugging priority and compression resistance so the intrinsic size has higher priority over the compression resistance.

The height constraint (the optional constraint directly at the right of the label) is set with a constant of 71, just the height for 4 lines. It never changes.

Then this same constraint has a priority switching between 747 and 749 so the following happens:

This works perfectly. My issue is that I can't figure out how to animate this constraint, since every solution animates the constant property and not the priority.

I would like to know if there's a solution or a workaround.

Upvotes: 3

Views: 1111

Answers (1)

Milan Nosáľ
Milan Nosáľ

Reputation: 19757

By experimenting with it, it seems that you cannot animate constraints using priorities, and you are stuck either with activating/deactivating constraints, or changing their constants.

I've had a similar task a couple of days ago. An easy but a bit naive approach is to drop the constraint and use only intrinsic content size - you can set the label.numberOfLines = 4 when it should be collapsed (thus the size won't expand over 4 lines), and label.numberOfLines = 0 when expanded. This is very easy and clean, however, I am not sure how that goes with animation.

A second approach is to use only the constraint and animate the constant. You have a height for 4 lines already, all you need is the height of the expanded label. You can use following extension on UILabel to calculate the height:

extension UILabel {
    func heightNeeded() -> CGFloat {
        self.layoutIfNeeded()
        let myText = self.text! as NSString
        let boundingRectangle = CGSize(width: self.bounds.width, height: CGFloat.greatestFiniteMagnitude)
        let labelSize = myText.boundingRect(with: boundingRectangle,
                                            options: .usesLineFragmentOrigin,
                                            attributes: [NSAttributedStringKey.font: self.font],
                                            context: nil)
        return labelSize.height
    }
}

Then all you need to animate is the:

labelHeightConstraint.constant = label.heightNeeded()

Don't forget on how to animate that constant using autolayout, see for example my following answer to another SO question.

Upvotes: 1

Related Questions