使用Autolayout以编程方式添加视图会出现'NSGenericException',原因是:'无法在视图上安装约束

时间:2013-08-05 14:28:26

标签: ios objective-c cocoa-touch autolayout

我使用[self.view addSubview:myView]将视图添加为子视图。这在纵向模式下工作正常。但是,它在景观中根本不起作用。如何以编程方式添加布局约束?

我的视图目前看起来像是纵向矩形,我需要它在横向模式下看起来像横向矩形。

我尝试使用此代码来查看代码中的约束如何工作,但它总是会导致异常。代码是:

[self.view addSubview:_preView];
NSLayoutConstraint *myConstraint = [NSLayoutConstraint
 constraintWithItem:_preView
 attribute:NSLayoutAttributeBottom
 relatedBy:NSLayoutRelationEqual
 toItem:self.view.superview
 attribute:NSLayoutAttributeBottom
 multiplier:1.0
 constant:-239];
[_preView addConstraint:myConstraint];

这总是会导致异常。我知道上面的代码只是试图确保预览的底部高于主视图底部239px。但这也不起作用。

你能帮我解决这个问题,以便我能解决景观问题吗?

更新

生成的异常是:

2013-08-05 16:13:28.889 Sample Code[33553:c07] *** Terminating app due to uncaught exception 'NSGenericException', reason: 'Unable to install constraint on view. Does the constraint reference something from outside the subtree of the view? That's illegal. constraint:<NSLayoutConstraint:0x912c430 UIView:0x8561340.bottom == UILayoutContainerView:0x8257340.bottom - 20> view:<UIView: 0x85774e0; frame = (0 0; 320 568); opaque = NO; autoresize = W+H; autoresizesSubviews = NO; layer = <CALayer: 0x8577490>>' *** First throw call stack: (0x1a04012 0x173be7e 0x1a03deb 0x12ee4a0 0xbb983e 0xbb9a27 0xbb9b76 0xbb9d3b 0xbb9c4d 0x1c0d9 0x11395b3 0x19c3376 0x19c2e06 0x19aaa82 0x19a9f44 0x19a9e1b 0x24027e3 0x2402668 0x67fffc 0x2d3d 0x2c65) libc++abi.dylib: terminate called throwing an exception (lldb)

我在添加约束之前添加了子视图,所以我很确定视图是在层次结构中。

更新2

我在IB中将父视图的属性设置为“Autoresize Subviews”。现在,当设备转动时,子视图会转换为横向矩形,但它太窄。我现在需要代码来确保它的宽度正确吗?

3 个答案:

答案 0 :(得分:37)

有几点意见:

  1. 您的约束引用了toItem self.view.superview。我认为你的意思是self.view

  2. 您正在将约束添加到_preView,但您应该将其添加到self.view(如果您进行了上述更改;如果不是,则使用self.view.superview )。您始终将约束添加到最近的共享父级。

  3. 对于您以编程方式创建的观看次数,请务必将translatesAutoresizingMaskIntoConstraints设置为NO

    因此:

    _preView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:_preView];
    NSLayoutConstraint *myConstraint = [NSLayoutConstraint constraintWithItem:_preView
                                                                    attribute:NSLayoutAttributeBottom
                                                                    relatedBy:NSLayoutRelationEqual
                                                                       toItem:self.view
                                                                    attribute:NSLayoutAttributeBottom
                                                                   multiplier:1.0
                                                                     constant:-239];
    [self.view addConstraint:myConstraint];
    

  4. 离线聊天,最后两个观察结果:

    1. 你的约束条件含糊不清。将来,您可以通过在调试器中运行应用程序,在应用程序运行时点击暂停按钮(enter image description here),然后在(lldb)提示符下输入

      来识别它

      po [[UIWindow keyWindow] _autolayoutTrace]

      ambiguous layout

      如果您看到AMBIGUOUS LAYOUT,那么您的约束不是完全限定的(因此您将获得不可预测的行为)。如果添加缺少的约束,则应该能够消除此警告。

    2. 如果要为基于约束的视图设置动画,可以动态更改constant的{​​{1}}属性,而不是自行更改constraints属性。例如:

      frame

答案 1 :(得分:0)

从上面的代码中,有2个问题。 1.应将约束添加到父视图(self.view或self.view.superview,视情况而定)。 2.作为myConstraint一部分的项应存在于您添加约束的视图层次结构中。

我的建议是检查你的myConstraint是否可以用_preView和self.view形成,将_preView作为子视图添加到self.view,然后将myConstraint添加到self.view。

此外,理想情况下,约束应放在视图中的-(void)updateConstraints方法中(如果您有自定义视图),并且只要您希望调用updateConstraints,就应在视图中调用[self setNeedsUpdateConstraints];您的视图(在初始化视图后,轮换后等)。您不会直接调用updateConstraints。

答案 2 :(得分:0)

关于自动布局的内容很少。当您添加布局约束时,请确保它不含糊。不明确的布局会导致显示中出现未定义的行为。所以好主意是使用IB,它永远不会允许你创建一个模糊的布局,但你必须通过所有约束来确保它们是有效的。

如果您想以编程方式执行此操作,我建议您使用Visual language

在使用布局之前,先了解这些tips会很有帮助。