如何在Objective-C中以编程方式添加约束

7

我希望能够通过编程添加约束条件,以下是我使用的代码来添加顶部和左侧的约束条件。

NSLayoutConstraint *top = [NSLayoutConstraint constraintWithItem:label1
                                                       attribute:NSLayoutAttributeTop
                                                       relatedBy:NSLayoutRelationEqual
                                                          toItem:self.view
                                                       attribute:NSLayoutAttributeTop
                                                      multiplier:1
                                                        constant:110];


NSLayoutConstraint *left = [NSLayoutConstraint constraintWithItem:label1
                                                        attribute:NSLayoutAttributeLeading
                                                        relatedBy:NSLayoutRelationEqual
                                                           toItem:self.view
                                                        attribute:NSLayoutAttributeLeading
                                                       multiplier:1
                                                         constant:10];

我的视图控制器中添加了lable1。当我像这样在视图中添加这两个约束时:
[self.view addConstraint:top];
[self.view addConstraint:left];

它会在控制台显示错误,并且约束不会影响标签。

2016-02-09 19:36:59.824 testinMRC[99160:313382] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. 
    Try this: 
        (1) look at each constraint and try to figure out which you don't expect; 
        (2) find the code that added the unwanted constraint or constraints and fix it. 
(
    "<NSLayoutConstraint:0x7fa5c8738610 V:|-(110)-[UILabel:0x7fa5c8626940'Label']   (Names: '|':UIView:0x7fa5c86267b0 )>",
    "<NSIBPrototypingLayoutConstraint:0x7fa5c8628a70 'IB auto generated at build time for view with fixed frame' V:|-(88)-[UILabel:0x7fa5c8626940'Label']   (Names: '|':UIView:0x7fa5c86267b0 )>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x7fa5c8738610 V:|-(110)-[UILabel:0x7fa5c8626940'Label']   (Names: '|':UIView:0x7fa5c86267b0 )>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
2016-02-09 19:36:59.889 testinMRC[99160:313382] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. 
    Try this: 
        (1) look at each constraint and try to figure out which you don't expect; 
        (2) find the code that added the unwanted constraint or constraints and fix it. 
(
    "<NSLayoutConstraint:0x7fa5c87334b0 H:|-(10)-[UILabel:0x7fa5c8626940'Label']   (Names: '|':UIView:0x7fa5c86267b0 )>",
    "<NSIBPrototypingLayoutConstraint:0x7fa5c86285c0 'IB auto generated at build time for view with fixed frame' H:|-(188)-[UILabel:0x7fa5c8626940'Label'](LTR)   (Names: '|':UIView:0x7fa5c86267b0 )>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x7fa5c87334b0 H:|-(10)-[UILabel:0x7fa5c8626940'Label']   (Names: '|':UIView:0x7fa5c86267b0 )>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.

有人可以告诉我为什么出现这个错误吗?请帮我找到解决方案。

使用 Masonry 在程序中编写约束。 - Teja Nandamuri
最新的方法已在此处添加:https://dev59.com/AV0a5IYBdhLWcg3wNWXA#51531647 - Lal Krishna
3个回答

15
在您的情况下,错误清楚地表明您的视图存在冲突的约束条件。可能是因为您试图向已经具有Interface Builder设置的视图添加约束条件。即使您没有明确设置任何约束条件,IB在检测到缺少某些约束条件时也会为您提供它们。
我看到您在评论中提到您想通过编程方式完成所有操作。在这种情况下,请查看下面的代码片段:
- (void)viewDidLoad {
    [super viewDidLoad];

    UIView *view = [UIView new];
    view.backgroundColor = [UIColor redColor];

    [view setTranslatesAutoresizingMaskIntoConstraints:NO];

    [self.view addSubview:view];

    NSLayoutConstraint *left = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1 constant:100];
    NSLayoutConstraint *top = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1 constant:100];

    NSLayoutConstraint *height = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:50];
    NSLayoutConstraint *width = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:50];

    [self.view addConstraints:@[left, top]];
    [view addConstraints:@[height, width]];

}

很容易理解。正如您所看到的,我不得不为该视图添加宽度和高度约束条件,因为仅使用左侧和顶部不能完全描述其位置。

结果:

在此输入图片描述

我建议您尝试使用可视化格式语言。可以用更少的代码实现相同的效果。以下代码可以得到完全相同的结果:

NSArray *horizontal = [NSLayoutConstraint constraintsWithVisualFormat:@"|-100-[view(50)]" options:0 metrics:nil views:@{@"view" : view}];
NSArray *vertical = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-100-[view(50)]" options:0 metrics:nil views:@{@"view" : view}];

[self.view addConstraints:vertical];
[self.view addConstraints:horizontal];

如果这有帮助,请告诉我。干杯。


5
[view setTranslatesAutoresizingMaskIntoConstraints:NO]; 这是一个关键要求。意思是将 view 的自动布局属性设置为否,以满足特定的布局需求。 - Ahmed Khalaf

1
问题不在于你的代码,而是在于“IB auto generated at build time for view with fixed frame”消息:
如果您没有添加约束条件,Interface Builder会自动生成它们。您可以通过以下两种方式避免它:
- 在项目导航器中选择nib或storyboard,在文件检查器中取消选中“使用自动布局”。 - 在Interface Builder中添加一些约束条件,并将它们设置为“在构建时删除”。

1
第一个选项,取消“使用自动布局”可能会对项目产生巨大的影响,并要求OP切换到旧的“支架和弹簧”样式调整大小。您的第二个选项是添加缺失的约束并将它们标记为“在构建时删除”,似乎是一个更好的解决方案。 - Duncan C
我想在运行时创建标签。当标签在运行时创建时,上述代码是否正确? - Crazy Developer

0

看起来您的布局约束存在冲突。很可能在Storyboard中设置了一个约束,而您正在尝试以编程方式添加直接与之冲突的约束。

看起来您正在尝试在操作发生后将UIView移出屏幕。例如,按下按钮并将快乐的面孔图片从屏幕中央移动到左上角。

直接在代码中添加和删除约束可能会导致代码膨胀、单元测试和警告填满控制台,这可能会带来巨大的麻烦。

最好的方法是在Storyboard中创建主UIView,并有一个隐藏的占位符UIView,该UIView包含您想要在按下按钮后UIView具有的所有约束。然后,您可以通过编程方式切换所有UIView的约束。因此,您想要修改的视图将具有占位符的位置、宽度和高度,而占位符将具有您想要修改的视图的位置和高度。

这样,当您以编程方式更改布局约束时,您永远不会遇到此错误,因为Storyboard会捕获任何错误。

有一些开源项目可以让你在一两行代码内完成这个功能。(文档中还有一些YouTube视频教程) https://cocoapods.org/pods/SBP

安装完CocoaPods之后,你的代码应该会像这样

这是视图控制器中修改UIView和占位符UIView的代码

//UIView* viewBeforeChange
//UIView* hiddenViewAfterChange
[self switchViewConst:viewBeforeChange secondView:hiddenViewAfterChange];

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接