以编程方式创build布局约束

我知道很多人已经提出了很多关于这个问题的问题,但是即使有了答案,我也无法做到这一点。

当我处理故事板上的限制时,这很容易,但在代码中我很难。 例如,我尝试按照屏幕方向在右侧看到屏幕的高度。 这是我的代码:

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而不是像self.myView这样的局部variables?

在代码中使用“自动布局”时,设置框架不起作用。 所以你在上面的视图中指定了200的宽度,在你设置约束时并不意味着什么。 为了将视图的约束设置为明确的,需要四个东西:对于任何给定状态的x位置,y位置,宽度和高度。

目前在上面的代码中,只有两个(相对于superview的高度,和相对于superview的y位置)。 除此之外,根据视图超级视图的约束如何设置,您有两个必需的约束可能会发生冲突。 如果超级视图有一个必要的约束来指定它的高度是小于748的值,那么你会得到一个“不可满足的约束”例外。

事实上,在设置约束之前设置视图的宽度意味着什么。 它甚至不考虑旧的框架,并基于它为这些视图指定的所有约束来计算新的框架。 当在代码中处理自动布局时,我通常只是使用initWithFrame:CGRectZero创build一个新的视图initWithFrame:CGRectZero或者简单的init

要创build您在问题中口头描述的布局所需的约束集,您需要添加一些水平约束来限制宽度和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的超级视图最小高度为748pts。 myView的宽度是200pts,并有一个正确的填充等于标准的空间反对其超视图。

如果你只是喜欢视图来填充整个超视图的高度而不限制超视图的高度,那么你可以忽略视觉格式文本中的(>=748)参数。 如果你认为(>=748)参数是需要给它一个高度 – 你不要在这种情况下:使用栏( | )或空格( |--| )将视图固定到超视图的边缘-| )的语法,你给你的观点一个Y位置(固定在一个单一的边缘视图),和一个高度的Y位置(固定两边的观点),从而满足你的约束设置为视图。

关于你的第二个问题:

使用NSDictionaryOfVariableBindings(self.myView) (如果你有一个myView的属性设置),并提供给你的VFL在你的VFL文本中使用self.myView ,你可能会遇到一个例外,当自动布局试图parsing你的VFL文本。 它与字典键中的点符号以及试图使用valueForKeyPath:的系统有关。 在这里看到一个类似的问题和答案 。

嗨,我一直在使用这个页面很多的约束和“如何”。 我花了很长时间才意识到我需要:

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

Swift版本

更新了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 

方法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样式。
  • 另请参阅以编程方式创build约束文档。
  • 查看这个答案 ,增加一个钉住约束的类似例子。

关于你关于属性的第二个问题,只有当你在类中声明它的时候,你才可以使用self.myView 。 由于myView是一个局部variables,所以不能以这种方式使用它。 有关更多详细信息,我build议您通过声明的属性上的苹果文档,

为什么我不能像self.myView那样使用像self.myView这样的局部variables?

尝试使用:

 NSDictionaryOfVariableBindings(_view) 

而不是self.view

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

来自doc的示例:

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