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

时间:2015-07-02 13:37:39

标签: ios objective-c autolayout constraints

我有一个具有动态高度的视图,我正在尝试在运行时更改此视图高度优先级。

这是我的代码部分;

if (index == 0) {

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

} else if (index == 1) {

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

}

我正在使用按钮操作更改索引。当我运行此代码时,我收到此错误:

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

我在这里犯了什么错误?

8 个答案:

答案 0 :(得分:131)

NSLayoutConstraint class reference中所述:

  

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

使用优先级999而不是1000.从技术上讲,它绝对不是必需的,但它的优先级高于其他任何优先级。

答案 1 :(得分:32)

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

如果要在代码中创建约束,请确保在激活之前设置其优先级。例如:

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

这会导致运行时异常。

  

不支持将优先级从必需变为不安装约束(反之亦然)。

正确的顺序是:

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

答案 2 :(得分:6)

我们总是处理这个问题的方法是不改变约束常量,只改变优先级。例如,在您的情况下有两个高度限制。

 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)

如果你想隐藏视图,你:

heightConstraintTwo.priority = 999;

同样,如果你想要显示视图:

heightConstraintTwo.priority = 250;

答案 3 :(得分:2)

快速版本:

myContraint.priority = UILayoutPriority(999.0)

答案 4 :(得分:1)

根据NSLayoutConstraints class内的UIKit Module

  

如果约束的优先级小于   UILayoutPriorityRequired,然后它是可选的。优先级更高   在较低优先级约束之前满足约束。        约束满足不是全部或全无。如果约束' a == b'是可选的,这意味着我们将尝试最小化   ' ABS(A-B)&#39 ;.        此属性只能在初始设置或可选时进行修改。将约束添加到视图后,   如果优先级从/更改,则抛出异常   NSLayoutPriorityRequired。

示例: - 具有各种优先级的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])

         }  

答案 5 :(得分:1)

我希望这种情况能帮助某人: 我有两个约束,它们是彼此相对的,我的意思是不能同时满足它们,在接口构建器中,其中一个优先级为1000,而另一个优先级小于1000。当我在代码中更改它们时,出现此错误:

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

然后我刚刚在viewDidLoad函数中使用.defaultHigh和.defaultLow值对其进行了初始化,这解决了我的问题。

答案 6 :(得分:0)

现在,您可以按照约束使用IBOutlet连接,然后使用此代码。

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

答案 7 :(得分:0)

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

我能够通过为Storyboard中的特定约束创建IBOutlet NSLayoutConstraint来解决此问题,并将其优先级保持为1000,下面是修复代码。

if (!songStarted){   
      if (typeof song == 'undefined'){
          song = new Audio();
          song.src = 'audio/startuptheme.mp3';  
      }
      song.addEventListener('playing', (event) => {songStarted = true;}); 
      song.play(); 
} 

希望这会有所帮助!!!干杯