How can I change constraints priority in run time

为君一笑 提交于 2019-11-28 15:55:09

问题


I have a view which has dynamic height and I am trying to change this view height priority in run time.

Here is my part of code;

if (index == 0) {

    surveyViewHeightConstraint.constant = 0;
    surveyViewHeightConstraint.priority = 1000;

} else if (index == 1) {

    surveyViewHeightConstraint.constant = 163;
    surveyViewHeightConstraint.priority = 500;

}

I am changing index with a button action. When I run this code, I am getting this error:

*** Assertion failure in -[NSLayoutConstraint setPriority:], /SourceCache/Foundation/Foundation-1141.1/Layout.subproj/NSLayoutConstraint.m:174

What is my mistake in here?


回答1:


As stated in NSLayoutConstraint class reference:

Priorities may not change from nonrequired to required, or from required to nonrequired. An exception will be thrown if a priority of NSLayoutPriorityRequired in OS X or UILayoutPriorityRequired in iOS is changed to a lower priority, or if a lower priority is changed to a required priority after the constraints is added to a view. Changing from one optional priority to another optional priority is allowed even after the constraint is installed on a view.

Use priority 999 instead of 1000. It won't be absolutely required technically speaking, but it'll be a higher priority than anything else.




回答2:


I want to make a small addition to Cyrille's answer.

If you are creating constraint in code, make sure to set its priority before making it active. For instance:

surveyViewHeightConstraint = [NSLayoutConstraint constraintWithItem:self
                                               attribute:NSLayoutAttributeHeight
                                               relatedBy:NSLayoutRelationEqual
                                                  toItem:self.superview
                                               attribute:NSLayoutAttributeHeight
                                              multiplier:1
                                                constant:0];
surveyViewHeightConstraint.active = YES;
surveyViewHeightConstraint.priority = 999;

This would result in run-time exception.

Mutating a priority from required to not on an installed constraint (or vice-versa) is not supported.

Correct order is:

surveyViewHeightConstraint.priority = 999;
surveyViewHeightConstraint.active = YES;



回答3:


The way we have always handled this is by not changing the constraint constant, just the priority. For example, in your situation have two height constraints.

 heightConstraintOne (who's height is set in the storyboard at 150, and priority set at 750)
 heightConstraintTwo (who's height is set in the storyboard at 0, and priority set at 250)

if you want to hide the view, you:

heightConstraintTwo.priority = 999;

likewise, if you want to show the view:

heightConstraintTwo.priority = 250;



回答4:


Swift version:

myContraint.priority = UILayoutPriority(999.0)



回答5:


I hope this scenario help someone: I had two constraints, that they were opposite to each other, I mean they couldn't be satisfied in the same time, in interface builder one of them had 1000 priority and other had less than 1000 priority. when I changed them in the code, I had this error:

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Mutating a priority from required to not on an installed constraint (or vice-versa) is not supported. You passed priority 250 and the existing priority was 1000.'

then I just initialized them in viewDidLoad function with .defaultHigh and .defaultLow values and this fixed my problem.




回答6:


According to NSLayoutConstraints class inside UIKit Module

If a constraint's priority level is less than UILayoutPriorityRequired, then it is optional. Higher priority constraints are met before lower priority constraints. Constraint satisfaction is not all or nothing. If a constraint 'a == b' is optional, that means we will attempt to minimize 'abs(a-b)'. This property may only be modified as part of initial set up or when optional. After a constraint has been added to a view, an exception will be thrown if the priority is changed from/to NSLayoutPriorityRequired.

Example:- UIButton constraints with various priorities -

 func setConstraints() {
        buttonMessage.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint(item: buttonMessage, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1.0, constant: -10).isActive = true

        let leading = NSLayoutConstraint(item: buttonMessage, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1.0, constant: 10)

        leading.isActive = true


        let widthConstraint = NSLayoutConstraint(item: buttonMessage, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 100)

        let heightConstraint = NSLayoutConstraint(item: buttonMessage, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 50)


        let trailingToSuperView = NSLayoutConstraint(item: buttonMessage, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: 0)

        trailingToSuperView.priority = 999
        trailingToSuperView.isActive = true

        //leading.isActive = false//uncomment & check it will align to right of the View

        buttonMessage.addConstraints([widthConstraint,heightConstraint])

         }  



回答7:


Now you can , just take the IBOutlet connection for your constraints , then use this code .

self.webviewHeight.priority = UILayoutPriority(rawValue: 1000)


来源:https://stackoverflow.com/questions/31186187/how-can-i-change-constraints-priority-in-run-time

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