在ViewController的loadView中创建的自动调整视图的AutoLayout约束

时间:2013-04-28 09:37:04

标签: ios objective-c ios6 autolayout

我的UIViewController通过覆盖loadView方法创建其视图:

- (void)loadView {
    UIView *view = [[UIView alloc] init];
    view.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
    self.view = view;
}

现在我想切换到AutoLayout,因此添加

view.translatesAutoresizingMaskIntoConstraints = NO;

到loadView方法。现在我必须指定之前自动生成的相同约束。我的方法是用

覆盖updateViewConstraints
- (void)updateViewConstraints {
    if (0 == [[self.view constraints] count]) {
        NSDictionary* views = @{@"view" : self.view};

        [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[view]|" options:0 metrics:0 views:views]];
        [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[view]|" options:0 metrics:0 views:views]];
     }

    [super updateViewConstraints];
}

但我得到一个例外,因为我认为这种约束应该与超级视图一致:

*** 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.

那么,正确的Contraints如何看起来像?

4 个答案:

答案 0 :(得分:8)

您需要在superview上设置约束。通过传递“|”引用超级视图引起异常在视觉格式。如果您像下面那样更新代码,它将起作用:

- (void)updateViewConstraints {
    if (self.view.superview != nil && [[self.view.superview constraints] count] == 0) {
        NSDictionary* views = @{@"view" : self.view};

        [self.view.superview addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[view]|" options:0 metrics:0 views:views]];
        [self.view.superview addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[view]|" options:0 metrics:0 views:views]];
    }
   [super updateViewConstraints];
}

在实践中,您可能想要在超级视图上检查除0约束之外的其他内容,但这应该会有所帮助。

答案 1 :(得分:5)

您不必在根视图上设置约束,因为Matt Neuburg解释了Chapter 19 of his Programming iOS 6 book, in section Manual Layout

  

我们并不打算给我们的观点(self.view)一个合理的框架。这是因为我们依赖其他人来适当地构建视图。在这种情况下,“其他人”是窗口,它通过将视图控制器的视图适当地设置为根视图,然后将其作为子视图放入窗口之前响应将其rootViewController属性设置为视图控制器。

答案 2 :(得分:5)

CEarwood方法的问题在于它是一个ViewController,它的视图不是任何其他视图的子视图,因此调用self.view.subview只会导致nil。请记住,Apple文档和指南强烈建议UIViewController或多或少地占据整个屏幕(除了导航栏或标签栏等)。

Palimondo的答案基本上是正确的:你的UIViewController需要在loadView中初始化它的视图,但它不需要指定它的框架或约束,因为它们会自动设置为窗口的框架和约束。如果您没有自己实现loadView,这正是默认情况下完成的操作。

答案 3 :(得分:1)

我不确定您是否需要为窗口的根视图设置约束。

那就是说,你的约束看起来是正确的,我认为你得到的例外是因为:

    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[view]|" options:0 metrics:0 views:views]];

使用|表示视图的超级视图的表示法。作为根级别视图,它没有superview。这样的事情可能会更好:

- (void)loadView {
    UIView *customView = [[UIView alloc] init];
    [self.view addSubview:customView];
    NSDictionary* views = @{@"customView" : customView};

    [customView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[customView]|" options:0 metrics:0 views:views]];
    [customView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[customView]|" options:0 metrics:0 views:views]];
}