ios 如何在运行时更改约束优先级

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31186187/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 06:41:54  来源:igfitidea点击:

How can I change constraints priority in run time

iosobjective-cautolayoutconstraints

提问by Le'Kirdok

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?

我在这里有什么错误?

回答by Cyrille

As stated in NSLayoutConstraintclass reference:

NSLayoutConstraint类参考中所述

Priorities may not change from nonrequired to required, or from required to nonrequired. An exception will be thrown if a priority of NSLayoutPriorityRequiredin OS X or UILayoutPriorityRequiredin 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.

优先级不得从非必需变为必需,或从必需变为非必需。如果NSLayoutPriorityRequired在 OS X 或UILayoutPriorityRequirediOS中将优先级更改为较低的优先级,或者在将约束添加到视图后将较低的优先级更改为所需的优先级,则会引发异常。即使在视图上安装了约束之后,也允许从一个可选优先级更改为另一个可选优先级。

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

使用优先级 999 而不是 1000。从技术上讲,它不是绝对必需的,但它比其他任何东西都具有更高的优先级。

回答by Vipin

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

我想对 Cyrille 的回答做一点补充。

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;

For Swift version 4+

对于 Swift 版本 4+

constraintName.priority = UILayoutPriority(rawValue: 999)

回答by Alex

Swift version:

迅捷版:

myContraint.priority = UILayoutPriority(999.0)

回答by J Andrew McCormick

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;

回答by J Andrew McCormick

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:

我希望这个场景对某人有所帮助:我有两个约束,它们彼此相反,我的意思是它们不能同时满足,在界面构建器中,其中一个优先级为 1000,另一个优先级低于 1000。当我在代码中更改它们时,出现以下错误:

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.'

由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“不支持将优先级从必需的更改为未安装的约束(反之亦然)。您通过了优先级 250,现有的优先级为 1000。

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

然后我只是用 .defaultHigh 和 .defaultLow 值在 viewDidLoad 函数中初始化它们,这解决了我的问题。

回答by Hyman

According to NSLayoutConstraints classinside UIKit Module

NSLayoutConstraints classUIKit 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.

如果约束的优先级低于 UILayoutPriorityRequired,则它是可选的。在较低优先级约束之前满足较高优先级约束。约束满足不是全有或全无。如果约束 'a == b' 是可选的,这意味着我们将尝试最小化 'abs(ab)'。此属性只能作为初始设置的一部分或在可选时进行修改。将约束添加到视图后,如果优先级从 NSLayoutPriorityRequired 更改为/更改为 NSLayoutPriorityRequired,则会引发异常。

Example:- UIButtonconstraints with various priorities -

示例:-UIButton具有各种优先级的约束-

 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])

         }  

回答by Venkat057

I was facing the same issue. As some of the answer mentioned above in iOS 13 changing priority will work fine, However in iOS 12 it will lead to crash.

我面临着同样的问题。由于iOS 13更改优先级中上面提到的一些答案可以正常工作,但是在iOS 12中它会导致崩溃。

I was able to fix this problem by creating IBOutlet NSLayoutConstraint to that specific constraint in Storyboard retaining its priority to 1000, below is the code for fix.

我能够通过在 Storyboard 中为该特定约束创建 IBOutlet NSLayoutConstraint 来解决这个问题,保留其优先级为 1000,下面是修复代码。

if (Condition) {
    surveyViewHeightConstraint.constant = 0;
    surveyViewHeightConstraint.isActive = false;
} else if (index == 1) {
    surveyViewHeightConstraint.constant = 163;
    surveyViewHeightConstraint.isActive = True;
}

Hope this helps!!! Cheers

希望这可以帮助!!!干杯

回答by Kishore Kumar

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

现在您可以,只需将 IBOutlet 连接用于您的约束,然后使用此代码。

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