Can you change constraints in the code, which were originally set in interface builder?

I am playing around to learn interface builder constraints. My current project has a lot of subviews and constraints set, however, for the sake of asking my qustion, I reduced the scope down to the basics (read below).


Using interface builder, I added a UIView to my project and pinned it to the top, leading, trailing and bottom safe area. I then added a button and a TableView to the UIView, where the button is positioned on top of the TableView. The button and TableView are then added into a vertical StackView.


How it works

The TableView was configured with four rows where each row has a text string. When the button is clicked, the TableView is made visible (ie: isHidden=false) and the StackView height increases. One of the rows in the TableView is selected and the button title is updated with the text string associated with the row which was selected. The TableView is then hidden from view (ie: isHidden = true) and the StackView height decreases. This all works as expected


My Goal

When the TableView is hidden, I would like to decrease the height of my UIView by the same amount as the StackView decreases. When the TableView is made visible, I would like to increase the height of my UIView by the same amount as the StackView increases. Basically, the UIView height becomes variable based on whether the TableView is hidden or not hidden.


Question

I think I need to remove the "Bottom Alignment Constraint" for my UIView so it is no longer set to the bottom safe area, but then how can I set this constraint properly based on the variable size of the StackView ?


Important Note

If I simply decide not to assign a "Bottom Alignment Constraint" for my UIView to the safe area, then when I run my project, my compelte UIView is not seen, since the height of the UIView becomes 0. As a result, it seems like I need to have this bottom constraint set somehow

Accepted Reply

I will first answer your title question:

Can you change constraints in the code, which were originally set in interface builder?


The answer is an absolute YES.


1. Create an IBOutlet for the each constraint you want to change (control drag from the constraint in IB to the code).

- Give it a meaningful name, so that you understand later what you are dealing with, such as

@IBOutlet var xBuutonToTopStackConstrainst: NSLayoutConstraint!


2. in code, call

xBuutonToTopStackConstrainst.constant = 20

or disable it

xBuutonToTopStackConstrainst.isActive = false


Or change any other property, like the relation, the objects on which constraints apply…

Replies

I will first answer your title question:

Can you change constraints in the code, which were originally set in interface builder?


The answer is an absolute YES.


1. Create an IBOutlet for the each constraint you want to change (control drag from the constraint in IB to the code).

- Give it a meaningful name, so that you understand later what you are dealing with, such as

@IBOutlet var xBuutonToTopStackConstrainst: NSLayoutConstraint!


2. in code, call

xBuutonToTopStackConstrainst.constant = 20

or disable it

xBuutonToTopStackConstrainst.isActive = false


Or change any other property, like the relation, the objects on which constraints apply…

Thanks a lot. I will give it a try !

It is in fact a very flexible way to adapt some constraints (for instance depending on orientation)when it is too complicated to define in IB.

The capability to activate / deactivate is also useful.

In some cases, I define (in IB), 2 sets of constraints and desactivate one set (e.g. for landscape).

Then I activate / deactivate in code in veiwWillLayout.


Good luck, thanks to report and close the thread when OK.

Worked perfectly ... thanks !


Thanks for the orientation tip as well. I will be using this also :>)

I have been playing around with setting a constraint in code some more and ran into a little issue. I hacked around the issue myself but I am curious how others "really" resolve this issue.


Description

I have a MainUIView which is centered in main ViewController view. This MainUIVIew has trailing, leading and top constraints set to the safe area. I am setting the MainUIView "bottom" constraint manually in code using some math I perform based on the number of other views (buttons, labels, etc..) which exist within MainUIView.


In Portrait mode, my bottom constraint has a calculated value of "400". This works well and everything looks good in portrait mode. When I now rotate to landscape mode, the current bottom constraint of "400" is too large of a value to be applied in landscape mode since there is not enough room at the bottom of the screen to apply "400" as a constraint. As a result, the system throws a warning in the debug console during the "viewWillTransition( )" method, which states "unable to simultaneously satisfy constraints".


I cannot set a proper bottom constraint in code in the "viewWillTransition( )" method since the transition truly did not occur yet (ie: the other views within MainUIView (ie: buttons, labels, etc.) did not move around yet due to the transition to landscape mode)


Question

What do people do to avoid seeing a warning when transitioning from Portrait to Landscape (or vice versa) due to the constraint value in Portrait mode being too large to be applied when transistioning to Landscape mode?

You should try not do it in viewWillTransition, but in viewWillLayoutSubviews()


override func viewWillLayoutSubviews() {
       
        super.viewWillLayoutSubviews()
        // Let adapt some constraints
}

Thanks for the information.


It worked for me, however, I had to use "viewWillLayoutSubviews( )" and "viewDidLayoutSubviews( )" to resolve my issue.


I had to perform the following two updates to resolve my specific issue:


1) Update the MainUIView "bottom" constraint manually in the "viewWillLayoutSubviews( )" function.


This resolved the "unable to simultaneously satisfy constraints" warning produced by the system when transitioning from portrait to landscape, however, my MainUIView height (based on newly provided bottom constraint value) was still not as desired.


2) Update the MainUIView "bottom" constraint manually (again) in the "viewDidLayoutSubviews( )" function.


The bottom constraint I wanted to set manually is determined by doing some math involving the MainUIView "Top Safe Area" height. When flipping from Portrait to Landscape I discovered the MainUIView "Top Safe Area" height is not truly applied until after the "super.viewDidLayoutSubviews( )" is called.