Ios 通过自动布局以编程方式添加视图将提供';NSGenericException';,原因:';无法在视图上安装约束

Ios 通过自动布局以编程方式添加视图将提供';NSGenericException';,原因:';无法在视图上安装约束,ios,objective-c,cocoa-touch,autolayout,Ios,Objective C,Cocoa Touch,Autolayout,我正在使用[self.view addSubview:myView]将视图添加为子视图。这在纵向模式下工作良好。然而,它在景观中根本不起作用。如何以编程方式添加布局约束 我的视图当前看起来像肖像矩形,我需要它在横向模式下看起来像横向矩形 我尝试了这段代码来查看代码中的约束是如何工作的,但它总是导致异常。代码是: [self.view addSubview:_preView]; NSLayoutConstraint *myConstraint = [NSLayoutConstraint cons

我正在使用
[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示例代码[33553:c07]***由于未捕获的异常“NSGenericeException”而终止应用程序,原因:“无法在视图上安装约束”。约束是否引用了视图子树之外的内容?那是违法的。约束:视图:'
***第一次抛出调用堆栈:
(0x1a04012 0x173be7e 0x1a03deb 0x12ee4a0 0xbb983e 0xbb9a27 0xbb9b76 0xbb9d3b 0xbb9c4d 0x1c0d9 0x11395b3 0x19c3376 0x19c2e06 0x19AA82 0x19a9f44 0x19a9e1b 0x24027e3 0x2402668 0x67fffc 0x2d3d 0x2c65)
libc++abi.dylib:terminate调用引发异常
(lldb)

在添加约束之前,我已经添加了子视图,因此我非常确定该视图处于层次结构中

更新2


在IB中,我将父视图的属性设置为“自动调整子视图的大小”。当设备转动时,子视图现在转换为横向矩形,但其太窄。我现在需要代码来确保它的宽度正确,也许?

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

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


此外,约束最好放在视图中的
-(void)updateConstraints
方法中(如果您有自定义视图),并且您应该调用
[self-setNeedsUpdateConstraints]。您不会直接调用updateConstraints。

关于自动布局,几乎没有什么东西。添加布局约束时,请确保其不含糊。模棱两可的布局将导致显示中出现未定义的行为。所以最好使用IB,它永远不会让你创建一个模棱两可的布局,但你必须通过所有的约束来确保它们是有效的

如果你想做它的程序,我建议你使用


在使用布局之前,仔细阅读这些内容将很有帮助。

一些观察结果:

  • 您的约束引用了
    self.view.superview
    toItem
    。我想你是指
    self.view

  • 您正在将约束添加到
    \u preView
    ,但是您应该将其添加到
    self.view
    (如果您进行了上述更改,则使用
    self.view.superview
    )。始终将约束添加到最近的共享父对象

  • 对于以编程方式创建的视图,请确保将
    translatesAutoResizezingMaskintoConstraints
    设置为
    NO

    因此:


  • 与您离线聊天,最后两个观察结果:

  • 你的约束是模糊的。将来,您可以在调试器中运行应用程序,在应用程序运行时按暂停按钮(),然后在
    (lldb)
    提示符下输入

    po[[UIWindow keyWindow]\u autolayoutTrace]

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

  • 如果要为基于约束的视图设置动画,可以设置更改
    约束
    常量
    属性的动画,而不是自己更改
    属性。例如:

        // 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 (i.e. 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];
                             }];
        });
    

  • 它会给您带来什么异常?您是否为编程创建的视图将
    translatesAutosizingMaskIntoConstraints
    设置为
    NO
    ?可能重复,因此我添加了此方法-(void)updateConstraints{NSLayoutConstraint*myConstraint=[NSLayoutConstraint constraintWithItem:_预览属性:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual-toItem:self.view.superview属性:NSLayoutAttributeBottom乘数:1.0常量:-20];[self.view添加约束:myConstraint];}并在加载动画后调用该方法:[self.view setNeedsUpdateConstraints];但它仍然会导致我提到的例外情况,即您在myConstraint中引用的视图应该是添加约束的视图层次结构的一部分。因此,如果您的myConstraint用于预览和self.view.superview,则必须将约束添加到self.view.superview。此外,预览应该已经添加到se中在调用约束之前使用lf.view或self.view.superview。您得到了什么异常?请同时提供它。基于该异常,问题是我所描述的。您试图对添加约束的视图树之外的某个对象(self.view.superview)使用约束(_preView或self.view)。将您的约束添加到self.view.supervie
        // 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 (i.e. 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];
                             }];
        });