I've set up multiple sets of constraints in IB, and I'd like to programmatically toggle between them depending on some state. There's a constraintsA
outlet collection all of which are marked as installed from IB, and a constraintsB
outlet collection all of which are uninstalled in IB.
I can programmatically toggle between the two sets like so:
NSLayoutConstraint.deactivateConstraints(constraintsA)
NSLayoutConstraint.activateConstraints(constraintsB)
But... I can't figure out when to do that. It seems like I should be able to do that once in viewDidLoad
, but I can't get that to work. I've tried calling view.updateConstraints()
and view.layoutSubviews()
after setting the constraints, but to no avail.
I did find that if I set the constraints in viewDidLayoutSubviews
everything works as expected. I guess I'd like to know two things...
- Why am I getting this behavior?
- Is it possible to activate/deactivate constraints from viewDidLoad?
The proper time to deactivate unused constraints:
Keep in mind that
viewWillLayoutSubviews
could be called multiple times, so no heavy calculations here, okay?Note: if you want to reactive some of the constraints later, then always store
strong
reference to them.I have found as long as you set up the constraints per normal in the override of
- (void)updateConstraints
(objective c), with astrong
reference for the initiality used active and un-active constraints. And elsewhere in the view cycle deactivate and/or activate what you need, then callinglayoutIfNeeded
, you should have no issues.The main thing is not to constantly reuse the override of
updateConstraints
and to separate the activations of the constraints, as long as you callupdateConstraint
s after your first initialization and layout. It does seem to matter after that where in the view cycle.I believe the problem you are experiencing is due to constraints not being added to their views until AFTER
viewDidLoad()
is called. You have a number of options:A) You can connect your layout constraints to an IBOutlet and access them in your code by these references. Since the outlets are connected before
viewDidLoad()
kicks off, the constraints should be accessible and you can continue to activate and deactivate them there.B) If you wish to use UIView's
constraints()
function to access the various constraints you must wait forviewDidLayoutSubviews()
to kick off and do it there, since that is the first point after creating a view controller from a nib that it will have any installed constraints. Don't forget to calllayoutIfNeeded()
when you're done. This does have the disadvantage that the layout pass will be performed twice if there are any changes to apply and you must ensure that there is no possibility that an infinite loop will be triggered.A quick word of warning: disabled constraints are NOT returned by the
constraints()
method! This means if you DO disable a constraint with the intention of turning it back on again later you will need to keep a reference to it.C) You can forget about the storyboard approach and add your constraints manually instead. Since you're doing this in
viewDidLoad()
I assume that the intention is to only do it once for the full lifetime of the object rather than changing the layout on the fly, so this ought to be an acceptable method.I activate and deactivate
NSLayoutConstraints
inviewDidLoad
, and I do not have any problems with it. So it does work. There must be a difference in setup between your app and mine :-)I'll just describe my setup - maybe it can give you a lead:
@IBOutlets
for all the constraints that I need to activate/deactivate.ViewController
, I save the constraints into class properties that are not weak. The reason for this is that I found that after deactivating a constraint, I could not reactivate it - it was nil. So, it seems to be deleted when deactivated.NSLayoutConstraint.deactivate/activate
like you do, I useconstraint.active = YES
/NO
instead.view.layoutIfNeeded()
.Maybe you could check your
@properties
, replaceweak
withstrong
.Sometimes it because
active = NO
setself.yourConstraint = nil
, so that you couldn't useself.yourConstraint
again.