ios 以编程方式创建布局约束
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12826878/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Creating layout constraints programmatically
提问by pierre23
I know that a lot people already asked tons of questions about this, but even with the answers I can't make it work.
我知道很多人已经问过很多关于这个的问题,但即使有了答案,我也无法让它发挥作用。
When I'm dealing with constraints on storyboard, it's easy but in code I have a hard time. I try, for example, to have a view that stays on the right side and has the height of the screen according the screen orientation. This is my code:
当我处理故事板上的约束时,这很容易,但在代码中我很难。例如,我尝试让视图停留在右侧并根据屏幕方向具有屏幕高度。这是我的代码:
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)]];
It doesn't satisfy some constraints. I don't see what is wrong. Also, why can't I use a property like self.myView
instead of a local variable like myView
?
它不满足某些约束。我看不出有什么问题。另外,为什么我不能使用像这样的属性self.myView
而不是像这样的局部变量myView
?
回答by larsacus
When using Auto Layout in code, setting the frame does nothing. So the fact that you specified a width of 200 on the view above, doesn't mean anything when you set constraints on it. In order for a view's constraint set to be unambiguous, it needs four things: an x-position, a y-position, a width, and a height for any given state.
在代码中使用自动布局时,设置框架没有任何作用。因此,您在上面的视图中指定宽度为 200 的事实在您对其设置约束时没有任何意义。为了使视图的约束集明确无误,它需要四件事:任何给定状态的 x 位置、y 位置、宽度和高度。
Currently in the code above, you only have two (height, relative to the superview, and y-position, relative to the superview). In addition to this, you have two required constraints that could conflict depending on how the view's superview's constraints are setup. Ifthe superview were to have a required constraint that specifies it's height be some value less than 748, you will get an "unsatisfiable constraints" exception.
目前在上面的代码中,您只有两个(高度,相对于父视图,y 位置,相对于父视图)。除此之外,您还有两个必需的约束可能会发生冲突,具体取决于视图的超视图约束的设置方式。如果父视图有一个必需的约束,指定它的高度小于 748,你将得到一个“不可满足的约束”异常。
The fact that you've set the width of the view before setting constraints means nothing. It will not even take the old frame into account and will calculate a new frame based on all of the constraints that it has specified for those views. When dealing with autolayout in code, I typically just create a new view using initWithFrame:CGRectZero
or simply init
.
在设置约束之前设置视图的宽度这一事实毫无意义。它甚至不会考虑旧框架,而是根据它为这些视图指定的所有约束来计算新框架。在代码中处理自动布局时,我通常只是使用initWithFrame:CGRectZero
或 简单地创建一个新视图init
。
To create the constraint set required for the layout you verbally described in your question, you would need to add some horizontal constraints to bound the width and x-position in order to give a fully-specified layout:
要创建您在问题中口头描述的布局所需的约束集,您需要添加一些水平约束来限制宽度和 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)]];
Verbally describing this layout reads as follows starting with the vertical constraint:
从垂直约束开始,口头描述此布局如下:
myView will fill its superview's height with a top and bottom padding equal to the standard space. myView's superview has a minimum height of 748pts. myView's width is 200pts and has a right padding equal to the standard space against its superview.
myView 将使用等于标准空间的顶部和底部填充填充其父视图的高度。myView 的超级视图的最小高度为 748pts。myView 的宽度为 200pts,并且右侧边距等于其父视图的标准空间。
If you would simply like the view to fill the entire superview's height without constraining the superview's height, then you would just omit the (>=748)
parameter in the visual format text. If you think that the (>=748)
parameter is required to give it a height - you don't in this instance: pinning the view to the superview's edges using the bar (|
) or bar with space (|-
, -|
) syntax, you are giving your view a y-position (pinning the view on a single-edge), and a y-position with height (pinning the view on both edges), thus satisfying your constraint set for the view.
如果您只是希望视图填充整个超级视图的高度而不限制超级视图的高度,那么您只需省略(>=748)
视觉格式文本中的参数。如果您认为该(>=748)
参数需要为其提供高度 - 在这种情况下您不需要:使用 bar ( |
) 或 bar 和空格 ( |-
, -|
) 语法将视图固定到超级视图的边缘,您将给您的视图一个 y -position(将视图固定在单边上)和带有高度的 y 位置(将视图固定在两条边上),从而满足您为视图设置的约束。
In regards to your second question:
关于你的第二个问题:
Using NSDictionaryOfVariableBindings(self.myView)
(if you had an property setup for myView) and feeding that into your VFL to use self.myView
in your VFL text, you will probably get an exception when autolayout tries to parse your VFL text. It has to do with the dot notation in dictionary keys and the system trying to use valueForKeyPath:
. See here for a similar question and answer.
使用NSDictionaryOfVariableBindings(self.myView)
(如果您为 myView 设置了属性)并将其输入您的 VFL 以self.myView
在您的 VFL 文本中使用,当自动布局尝试解析您的 VFL 文本时,您可能会遇到异常。它与字典键中的点符号和尝试使用valueForKeyPath:
. 请参阅此处以获取类似的问答。
回答by BriOnH
Hi I have been using this page a lot for constraints and "how to". It took me forever to get to the point of realizing I needed:
嗨,我一直在使用这个页面来限制和“如何做”。我花了很长时间才意识到我需要:
myView.translatesAutoresizingMaskIntoConstraints = NO;
to get this example to work. Thank you Userxxx, Rob M. and especially larsacus for the explanation and code here, it has been invaluable.
让这个例子工作。感谢 Userxxx、Rob M. 特别是 larsacus 在这里的解释和代码,它非常宝贵。
Here is the code in full to get the examples above to run:
以下是让上述示例运行的完整代码:
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)]];
回答by Suragch
Swift version
迅捷版
Updated for Swift 3
为 Swift 3 更新
This example will show two methods to programmatically add the following constraints the same as if doing it in the Interface Builder:
这个例子将展示两种方法来以编程方式添加以下约束,就像在 Interface Builder 中一样:
Width and Height
宽度和高度
Center in Container
集装箱中心
Boilerplate code
样板代码
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)
// ...
}
Method 1: Anchor Style
方法一:锚式
// 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
Method 2: NSLayoutConstraint Style
方法二: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
Notes
笔记
- Anchor style is the preferred method over
NSLayoutConstraint
Style, however it is only available from iOS 9, so if you are supporting iOS 8 then you should still useNSLayoutConstraint
Style. - See also the Programmatically Creating Constraintsdocumentation.
- See this answerfor a similar example of adding a pinning constraint.
回答by iDev
Regarding your second question about properties, you can use self.myView
only if you declared it as a property in class. Since myView
is a local variable, you can not use it that way. For more details on this, I would recommend you to go through the apple documentation on Declared Properties,
关于关于属性的第二个问题,self.myView
只有在类中将其声明为属性时才能使用。由于myView
是局部变量,因此您不能以这种方式使用它。有关这方面的更多详细信息,我建议您阅读有关Declared Properties的苹果文档,
回答by Megarushing
why can't I use a property like self.myView
instead of a local variable like myView?
为什么我不能使用类似的属性self.myView
而不是像 myView这样的局部变量?
try using:
尝试使用:
NSDictionaryOfVariableBindings(_view)
instead of self.view
代替 self.view
回答by andreacipriani
Please also note that from iOS9 we can define constraints programmatically "more concise, and easier to read"using subclasses of the new helper class NSLayoutAnchor.
另请注意,从 iOS9 开始,我们可以使用新帮助类NSLayoutAnchor 的子类以编程方式定义约束“更简洁,更易于阅读”。
An example from the doc:
文档中的一个示例:
[self.cancelButton.leadingAnchor constraintEqualToAnchor:self.saveButton.trailingAnchor constant: 8.0].active = true;