使用自动布局以编程方式添加视图给出'NSGenericException',原因:'无法在视图上安装约束

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

我的看法目前看起来像肖像矩形,我需要它看起来像横向模式的景观矩形。

我试过这段代码,看看代码中的约束是如何工作的,但总是会导致exception。 代码是:

 [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。 但是这也行不通。

你能帮我解决这个问题吗?

UPDATE

生成的exception是:

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”。 当设备被转动时,子视图现在转换成横向矩形,但是太窄。 我现在需要的代码,以确保其正确的宽度可能?

几点意见:

  1. 您的约束引用了toItem 。 我假设你的意思是self.view

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

  3. 对于以编程方式创build的视图,请确保将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]; 

离线聊天给你,两个最后的意见:

  1. 你的约束是模棱两可的。 将来,您可以通过在debugging器中运行应用程序,在应用程序运行时点击暂停button 在这里输入图像说明 ),然后在(lldb)提示符下,您可以input

    po [[UIWindow keyWindow] _autolayoutTrace]

    模糊的布局

    如果你看到AMBIGUOUS LAYOUT ,那么你的约束不完全合格(因此你会得到不可预知的行为)。 如果添加缺less的约束,您应该能够消除此警告。

  2. 如果要为基于约束的视图设置animation效果,则可以dynamic改变constraintsconstant属性,而不是通过自己更改frame属性。 例如:

      // create subview UIView *subview = [[UIView alloc] init]; subview.backgroundColor = [UIColor lightGrayColor]; subview.translatesAutoresizingMaskIntoConstraints = NO; [self.view addSubview:subview]; // create dictionary for VFL commands NSDictionary *views = @{@"subview" : subview, @"superview" : self.view}; // add horizontal constraints [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[subview]|" options:0 metrics:nil views:views]]; // set the height of the offscreen subview to be the same as its superview [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[subview(==superview)]" options:0 metrics:nil views:views]]; // set the location of the subview to be just off screen below the current view NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:self.view.bounds.size.height]; [self.view addConstraint:constraint]; // then in two seconds, animate this subview back on-screen (ie change the top constraint `constant` to zero) double delayInSeconds = 2.0; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ constraint.constant = 0.0; [UIView animateWithDuration:1.0 animations:^{ [self.view layoutIfNeeded]; }]; }); 

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

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

另外,约束应该放在你的视图中的-(void)updateConstraints方法中(如果你有自定义视图),你应该调用[self setNeedsUpdateConstraints]; 在你的视图中,只要你想在你的视图上调用updateConstraints(初始化你的视图后,旋转等)。 你不会直接调用updateConstraints。

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

如果你想以编程方式做,我会build议你使用Visual语言 。

在使用布局之前,通过这些提示会很有帮助。