以编程方式创建布局约束

时间:2012-10-10 19:28:08

标签: objective-c ios constraints autolayout

我知道很多人已经就此问了很多问题,但即使有了答案,我也无法使其发挥作用。

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

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)]];

它不满足某些约束。我没有看到什么是错的。另外,为什么我不能使用像self.myView这样的属性而不是myView这样的局部变量?

6 个答案:

答案 0 :(得分:106)

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

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

在设置约束之前设置视图宽度这一事实并不意味着什么。它甚至不会考虑旧框架,并将根据它为这些视图指定的所有约束来计算新框架。在处理代码中的自动布局时,我通常只使用initWithFrame:CGRectZeroinit创建新视图。

要创建您在问题中口头描述的布局所需的约束集,您需要添加一些水平约束来绑定宽度和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将使用顶部和底部填充填充其superview的高度   等于标准空间。 myView的superview具有最小高度   748pts。 myView的宽度为200pts,右边的填充等于   反对其超级视图的标准空间。

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

关于你的第二个问题:

使用-|(如果您有myView的属性设置)并将其输入您的VFL以在您的VFL文本中使用NSDictionaryOfVariableBindings(self.myView),当autolayout尝试解析您的VFL时,您可能会遇到异常文本。它与字典键中的点表示法和尝试使用self.myView的系统有关。 See here for a similar question and answer

答案 1 :(得分: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)]];

答案 2 :(得分:10)

Swift版本

更新了Swift 3

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

宽度和高度

enter image description here

容器中心

enter image description here

Boilerplate代码

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

方法2: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样式。
  • 另请参阅Programmatically Creating Constraints文档。
  • 有关添加固定约束的类似示例,请参阅this answer

答案 3 :(得分:5)

关于有关属性的第二个问题,只有在课堂上将其声明为属性时,才能使用self.myView。由于myView是一个局部变量,因此不能以这种方式使用它。有关此问题的更多详细信息,我建议您浏览Declared Properties上的Apple文档,

答案 4 :(得分:5)

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

尝试使用:

NSDictionaryOfVariableBindings(_view)

而不是self.view

答案 5 :(得分:4)

请注意,从iOS9开始,我们可以使用新帮助程序类NSLayoutAnchor的子类以编程方式"更简洁,更易于阅读" 来定义约束。

来自doc的一个例子:

[self.cancelButton.leadingAnchor constraintEqualToAnchor:self.saveButton.trailingAnchor constant: 8.0].active = true;