8

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

4 回答 4

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 约束以外的其他内容,但这应该会有所帮助。

于 2013-05-04T19:45:27.480 回答
5

You don't have to set the constraints on your root view as Matt Neuburg explains the Chapter 19 of his Programming iOS 6 book, in section Manual Layout:

We have not bothered to give our view (self.view) a reasonable frame. This is because we are relying on someone else to frame the view appropriately. In this case, the “someone else” is the window, which responds to having its rootViewController property set to a view controller by framing the view controller’s view appropriately as the root view before putting it into the window as a subview.

于 2013-05-26T10:27:52.023 回答
5

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

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

于 2013-06-20T16:42:26.703 回答
1

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

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

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

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

- (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]];
}
于 2013-04-30T01:53:46.800 回答