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


86

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

这是我的代码部分;

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

我在这里有什么错?

Answers:


172

NSLayoutConstraint课程参考中所述

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

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


4
感谢您的答复,但是,如果我使用999而不是1000,则无法通过将0分配给高度约束来隐藏视图。
Le'Kirdok,2015年

那是另一个问题。您可能还有其他冲突的约束。如果您的代码不再崩溃,但视图动画仍然不正确,请将此问题标记为已解决;然后再打开一个。
Cyrille

不错,使用不同的值(
999、900、500

7
认真吗 在iOS开发中,什么工作正常吗?如此之多的事情必须手动完成和/或必须执行大量的变通方法代码,这些都是由于系统错误或不支持所致。抱歉,没有提供建设性的评论。
卢滕

6
似乎此限制已在iOS 13中删除。我尝试将约束从更改为requireddefaultLow并且它起作用了。用于碰撞iOS上12相同的代码
史蒂芬·范德维奇

52

我想对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;

对于Swift版本4+

constraintName.priority = UILayoutPriority(rawValue: 999)


8

我们一直处理此问题的方法是不更改约束常数,而只是更改优先级。例如,在您的情况下有两个高度限制。

 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;

5
很酷,知道了:使用999而不是1000。谢谢
brainray

3

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

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

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


1

根据NSLayoutConstraints class里面 UIKit Module

如果约束的优先级小于UILayoutPriorityRequired,则它是可选的。在较低优先级约束之前先满足较高优先级约束。约束满足不是全部或全部。如果约束'a == b'是可选的,则意味着我们将尝试最小化'abs(ab)'。只能在初始设置中或在可选时修改此属性。将约束添加到视图后,如果优先级从NSLayoutPriorityRequired更改为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])

         }  

1
不可以,您永远不要在中创建约束viewDidLayoutSubviews。可以多次调用该方法,如果在其中创建重复的约束,则可能会使您的应用程序崩溃。
每小时

0

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

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

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

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


-3

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

self.webviewHeight.priority = UILayoutPriority(rawValue: 1000)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.