When can I activate/deactivate layout constraints?

我的梦境 提交于 2019-11-27 11:37:36
Joachim Bøggild

I activate and deactivate NSLayoutConstraints in viewDidLoad, 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:

  1. I set up @IBOutlets for all the constraints that I need to activate/deactivate.
  2. In the 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.
  3. I do not use NSLayoutConstraint.deactivate/activate like you do, I use constraint.active = YES/NO instead.
  4. After setting the constraints, I call view.layoutIfNeeded().
Leo

Maybe you could check your @properties, replace weak with strong.

Sometimes it because active = NO set self.yourConstraint = nil, so that you couldn't use self.yourConstraint again.

override func viewDidLayoutSubviews() {
// do it here, after constraints have been materialized
}

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 for viewDidLayoutSubviews() 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 call layoutIfNeeded() 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.

You can also adjust the priority property to "enable" and "disable" them (750 value to enable and 250 to disable for example). For some reason changing the active BOOL didn't had any effect on my UI. No need for layoutIfNeeded and can be set and changed at viewDidLoad or any time after that.

The proper time to deactivate unused constraints:

-(void)viewWillLayoutSubviews{
    [super viewWillLayoutSubviews];

    self.myLittleConstraint.active = NO;
}

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 a strong reference for the initiality used active and un-active constraints. And elsewhere in the view cycle deactivate and/or activate what you need, then calling layoutIfNeeded, 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 call updateConstraints after your first initialization and layout. It does seem to matter after that where in the view cycle.

Sumeet

When a view is being created the following life cycle methods are called in order:

  1. loadView
  2. viewDidLoad
  3. viewWillAppear
  4. viewWillLayoutSubviews
  5. viewDidLayoutSubviews
  6. viewDidAppear

Now to your questions.

  1. Why am I getting this behavior?

Answer: Because when you try to set the constraints on the views in viewDidLoad the view does not have its bounds, hence constraints cannot be set. It's only after viewDidLayoutSubviews that the view's bounds are finalized.

  1. Is it possible to activate/deactivate constraints from viewDidLoad?

Answer: No. Reason explained above.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!