Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change layout constraint programmatically in Swift?

I have a collection view which has a textView for each cell. This is my textview constraint set up

textView.topAnchor.constraint(equalTo: object1.bottomAnchor).isActive = true
textView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true

...and width and height of my textView.

Now, I want to change topAnchor of my textView to object 2 bottom anchor instead of object 1 bottom anchor due to a if condition. However, when I enter the code below, I get Will attempt to recover by breaking constraint error.

Does anyone know a way to change top anchor once it is already set up?

if (aCondition){
textView.topAnchor.constraint(equalTo: object2.bottomAnchor).isActive = true
}else{
  textView.topAnchor.constraint(equalTo: object1.botttomAnchor).isActive = true
}
like image 737
KevinVuD Avatar asked Mar 18 '18 09:03

KevinVuD


People also ask

How do I change constraints in Xcode?

Some editing is also possible directly from the Size inspector. Clicking the Edit button in any of the constraints brings up a popover where you can change the constraint's relationship, constant, priority, or multiplier.

How do I change the constraint multiplier in Swift?

Since multiplier is a read-only property and you can't change it, you need to replace the constraint with its modified clone.


1 Answers

You have to deactivate the old active constraint. Right now you are just adding new constraints to the view. So first I would suggest you create two properties that would keep references to constraints:

fileprivate var topConstraint1: NSLayoutConstraint?
fileprivate var topConstraint2: NSLayoutConstraint?

Then at the beginning, when you are creating UI, initialize them properly:

topConstraint1 = textView.topAnchor.constraint(equalTo: object1.bottomAnchor)
topConstraint2 = textView.topAnchor.constraint(equalTo: object2.bottomAnchor)

And activate the one that you want to be active as first:

topConstraint1?.isActive = true

Then when you want to change the constraints, you first deactivate the one that should be deactivated, and then activate the correct one:

if aCondition {
    topConstraint1?.isActive = false
    topConstraint2?.isActive = true
} else {
    topConstraint2?.isActive = false
    topConstraint1?.isActive = true
}

P.S.: You always want to first deactivate the old one and then activate the new one, otherwise for that moment when you activate the new one it would conflict with the old one and cause warnings in console.

P.S.2: If you want to activate several constraints at once, use NSLayoutConstraint.activate(_:) - as per documentation, it is more efficient:

Typically, using this method is more efficient than activating each constraint individually.

So e.g., instead of:

someConstraint1.isActive = true
someConstraint2.isActive = true

use rather:

NSLayoutConstraint.activate([someConstraint1, someConstraint2])

The same applies to deactivating constraints and NSLayoutConstraint.deactivate(_:).

like image 137
Milan Nosáľ Avatar answered Sep 23 '22 13:09

Milan Nosáľ