84

我知道很多人已经问了很多关于这个的问题,但即使有了答案,我也无法让它发挥作用。

当我处理情节提要上的约束时,这很容易,但在代码中我很难。例如,我尝试让视图保持在右侧并根据屏幕方向具有屏幕高度。这是我的代码:

UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 748)];
myView.backgroundColor = [UIColor redColor];
[self.view addSubview:myView];
[self.view addConstraints:[NSLayoutConstraint
    constraintsWithVisualFormat:@"V:|-[myView(>=748)]-|"
    options:0 metrics:nil
    views:NSDictionaryOfVariableBindings(myView)]];

它不满足某些约束。我看不出有什么问题。另外,为什么我不能使用属性 likeself.myView而不是局部变量 like myView

4

6 回答 6

106

在代码中使用自动布局时,设置框架什么都不做。因此,您在上面的视图中指定宽度为 200 的事实在您对其设置约束时没有任何意义。为了使视图的约束集明确,它需要四个东西:任何给定状态的 x 位置、y 位置、宽度和高度。

目前在上面的代码中,您只有两个(高度,相对于超级视图,和 y 位置,相对于超级视图)。除此之外,您还有两个必需的约束,它们可能会根据视图的超级视图约束的设置方式而发生冲突。如果超级视图有一个必需的约束,指定它的高度小于 748,你将得到一个“不可满足的约束”异常。

在设置约束之前设置视图的宽度这一事实没有任何意义。它甚至不会考虑旧框架,而是会根据它为这些视图指定的所有约束来计算新框架。在代码中处理自动布局时,我通常只是使用initWithFrame:CGRectZero或简单地创建一个新视图init

要创建您在问题中口头描述的布局所需的约束集,您需要添加一些水平约束来限制宽度和 x 位置,以便提供完全指定的布局:

[self.view addConstraints:[NSLayoutConstraint
    constraintsWithVisualFormat:@"V:|-[myView(>=748)]-|"
    options:NSLayoutFormatDirectionLeadingToTrailing
    metrics:nil
    views:NSDictionaryOfVariableBindings(myView)]];

[self.view addConstraints:[NSLayoutConstraint
    constraintsWithVisualFormat:@"H:[myView(==200)]-|"
    options:NSLayoutFormatDirectionLeadingToTrailing
    metrics:nil
    views:NSDictionaryOfVariableBindings(myView)]];

从垂直约束开始,口头描述此布局如下:

myView 将使用等于标准空间的顶部和底部填充填充其超级视图的高度。myView 的 superview 的最小高度为 748pts。myView 的宽度是 200pts 并且有一个右边的填充等于它的 superview 的标准空间。

如果您只是希望视图填充整个超级视图的高度而不限制超级视图的高度,那么您只需省略(>=748)可视格式文本中的参数。如果您认为需要该(>=748)参数来给它一个高度 - 在这种情况下您不需要:使用 bar ( |) 或带有空格 ( |-, -|) 语法的 bar 将视图固定到超级视图的边缘,您正在给您的视图一个 y -position (将视图固定在单边上)和带有高度的 y 位置(将视图固定在两条边上),从而满足您为视图设置的约束。

关于你的第二个问题:

使用NSDictionaryOfVariableBindings(self.myView)(如果您为 myView 设置了属性)并将其输入您的 VFL 以self.myView在您的 VFL 文本中使用,当自动布局尝试解析您的 VFL 文本时,您可能会遇到异常。它与字典键中的点符号和尝试使用的系统有关valueForKeyPath:有关类似的问题和答案,请参见此处

于 2012-10-24T18:54:39.083 回答
61

嗨,我一直在使用此页面进行限制和“如何”。我花了很长时间才意识到我需要:

myView.translatesAutoresizingMaskIntoConstraints = NO;

让这个例子工作。感谢 Userxxx、Rob M. 尤其是 larsacus 在这里的解释和代码,它非常宝贵。

以下是运行上述示例的完整代码:

UIView *myView = [[UIView alloc] init];
myView.backgroundColor = [UIColor redColor];
myView.translatesAutoresizingMaskIntoConstraints = NO;  //This part hung me up 
[self.view addSubview:myView];
//needed to make smaller for iPhone 4 dev here, so >=200 instead of 748
[self.view addConstraints:[NSLayoutConstraint
                           constraintsWithVisualFormat:@"V:|-[myView(>=200)]-|"
                           options:NSLayoutFormatDirectionLeadingToTrailing
                           metrics:nil
                           views:NSDictionaryOfVariableBindings(myView)]];

[self.view addConstraints:[NSLayoutConstraint
                           constraintsWithVisualFormat:@"H:[myView(==200)]-|"
                           options:NSLayoutFormatDirectionLeadingToTrailing
                           metrics:nil
                           views:NSDictionaryOfVariableBindings(myView)]];
于 2013-02-13T02:36:19.000 回答
11

斯威夫特版本

为 Swift 3 更新

此示例将显示两种以编程方式添加以下约束的方法,就像在 Interface Builder 中一样:

宽度和高度

在此处输入图像描述

集装箱中心

在此处输入图像描述

样板代码

override func viewDidLoad() {
    super.viewDidLoad()

    // set up the view
    let myView = UIView()
    myView.backgroundColor = UIColor.blue
    myView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(myView)

    // Add constraints code here (choose one of the methods below)
    // ...
}

方法1:锚样式

// width and height
myView.widthAnchor.constraint(equalToConstant: 200).isActive = true
myView.heightAnchor.constraint(equalToConstant: 100).isActive = true

// center in container
myView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
myView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true

方法二:NSLayoutConstraint 样式

// width and height
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 200).isActive = true
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 100).isActive = true

// center in container
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.centerX, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.centerX, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.centerY, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.centerY, multiplier: 1, constant: 0).isActive = true

笔记

  • 锚样式是比NSLayoutConstraint样式更受欢迎的方法,但是它仅适用于 iOS 9,因此如果您支持 iOS 8,那么您仍然应该使用NSLayoutConstraint样式。
  • 另请参阅以编程方式创建约束文档。
  • 有关添加固定约束的类似示例,请参见此答案。
于 2016-04-01T04:49:03.567 回答
5

关于您关于属性的第二个问题,self.myView只有在将其声明为类中的属性时才能使用。由于myView是局部变量,因此您不能那样使用它。有关这方面的更多详细信息,我建议您阅读有关声明属性的苹果文档,

于 2012-10-10T23:04:37.737 回答
5

为什么我不能使用像 myView 这样的属性self.myView而不是像 myView 这样的局部变量?

尝试使用:

NSDictionaryOfVariableBindings(_view)

代替self.view

于 2013-03-06T22:23:00.277 回答
4

另请注意,从 iOS9 开始,我们可以使用新的辅助类NSLayoutAnchor的子类以编程方式定义约束“更简洁、更易于阅读”

文档中的一个例子:

[self.cancelButton.leadingAnchor constraintEqualToAnchor:self.saveButton.trailingAnchor constant: 8.0].active = true;
于 2015-12-23T14:29:00.137 回答