使用swift的代码中的约束-无法激活
我正试图理解自动布局约束。在Ray W教程挑战之后(没有解决方案或讨论),布局应如下所示: 在IB中做这件事很容易——创建一个宽度和高度都相同的黄色视图,垂直居中,水平固定在边缘;然后在该视图中创建带有简单约束的标签、字段和按钮 我的第一个问题是:如果标签具有固有的内容大小,而其他所有内容都固定在黄色视图上,那么为什么需要定义固定的宽度和高度?为什么它不能从其子视图的固有内容推断宽度和高度 继续并尝试在代码中重新创建此布局时出现错误: 由于未捕获异常“NSGenericeException”而终止应用程序, 原因:“无法激活带有项的约束使用swift的代码中的约束-无法激活,swift,autolayout,nslayoutconstraint,Swift,Autolayout,Nslayoutconstraint,我正试图理解自动布局约束。在Ray W教程挑战之后(没有解决方案或讨论),布局应如下所示: 在IB中做这件事很容易——创建一个宽度和高度都相同的黄色视图,垂直居中,水平固定在边缘;然后在该视图中创建带有简单约束的标签、字段和按钮 我的第一个问题是:如果标签具有固有的内容大小,而其他所有内容都固定在黄色视图上,那么为什么需要定义固定的宽度和高度?为什么它不能从其子视图的固有内容推断宽度和高度 继续并尝试在代码中重新创建此布局时出现错误: 由于未捕获异常“NSGenericeException”而
和”
,因为它们没有共同的祖先。是吗
不同视图层次结构中的约束引用项?那是
非法的。”
第二个问题:这些层是什么,我的所有视图都在一个继承人视图中-superview包含黄色视图包含文本标签和字段
在经历了许多痛苦之后,我试图准确地重新创建IB中的约束,但这只增加了以下错误:
无法同时满足约束
(
"<NSLayoutConstraint:0x7ac57370 H:[UIView:0x7a96b6f0(0)]>",
"<NSLayoutConstraint:0x7ac57400 H:|-(8)-[UILabel:0x7a96bb50'Username:'] (Names: '|':UIView:0x7a96b6f0 )>",
"<NSLayoutConstraint:0x7ac57430 UILabel:0x7a96bb50'Username:'.trailing == UITextField:0x7a961020.leading + 8>",
"<NSLayoutConstraint:0x7ac57520 UITextField:0x7a961020.trailing == UIView:0x7a96b6f0.trailing - 8>" )
我的第一个问题是:如果标签具有固有的内容大小,
其他所有的东西都固定在黄色视图上,那我为什么需要它呢
要定义固定的宽度和高度?为什么它不能推断出宽度
与子视图的内在内容的距离和高度
用户名
和密码
字段没有宽度。它们通过固定在中心视图的左右边缘的标签上获得宽度。如果您添加了约束以赋予这些字段一个宽度,则centerView
可以根据其内容确定其宽度
继续并尝试用代码重新创建这个布局给了我一个机会
错误:由于未捕获异常“NSGenericeException”而终止应用程序,
原因:“无法激活项>和>的约束,因为它们
没有共同的祖先。约束是否引用中的项
不同的视图层次结构?这是违法的。”
第一个问题是没有将密码标签添加为子视图:
self.centerView.addSubview(passwordLabel)
这就是给你带来错误的原因。passwordLabel
不在视图层次结构中,因此自动布局不知道如何使用centerView
约束它
第二个问题是将centerView
的width
和height
设置为0
。尝试较大的值,如100
和300
:
let constraintCenterViewHeight = NSLayoutConstraint(item: centerView, attribute: .Height,
relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0,
constant: 100)
let constraintCenterViewWidth = NSLayoutConstraint(item: centerView, attribute: .Width,
relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0,
constant: 300)
第三个问题是,某些常量必须为负值:
// changed to -8
let constraintUsernameLabelHTrailing = NSLayoutConstraint(item: usernameLabel,
attribute: .Trailing, relatedBy: .Equal, toItem: usernameField,
attribute: .Leading, multiplier: 1.0, constant: -8)
// changed to -8
let constraintUsernameFieldVBottom = NSLayoutConstraint(item: usernameField,
attribute: .Bottom, relatedBy: .Equal, toItem: passwordField,
attribute: .Top, multiplier: 1.0, constant: -8)
// changed to -8
let constraintPasswordLabelHTrailing = NSLayoutConstraint(item: passwordLabel,
attribute: .Trailing, relatedBy: .Equal, toItem: passwordField,
attribute: .Leading, multiplier: 1.0, constant: -8)
我也犯了同样的错误,但发生的原因有所不同:
我得到错误是因为我在将视图添加到其superview之前引用了我的superview。我看了这段代码好几天,没有看到丢失的子视图,也没有看到宽度和高度为0!啊哈,(当我写这篇文章的时候,我没有明白)我那迟钝的老脑袋认为用户名标签的后缘到用户名字段的前缘应该是沿Y轴或水平轴再向前8点。但那只是又一个愚蠢的错误。我希望usernameLabel的后缘到usernameField的前缘沿Y轴或水平轴向后8点。非常抱歉,非常感谢你指出了这一点。如果您理解了这一点,很高兴知道这一点。这两行是目标(centerXAnchor和centerYAnchor),应该向所有stackView布局指南报告。你是今天的英雄,谢谢你。
// changed to -8
let constraintUsernameLabelHTrailing = NSLayoutConstraint(item: usernameLabel,
attribute: .Trailing, relatedBy: .Equal, toItem: usernameField,
attribute: .Leading, multiplier: 1.0, constant: -8)
// changed to -8
let constraintUsernameFieldVBottom = NSLayoutConstraint(item: usernameField,
attribute: .Bottom, relatedBy: .Equal, toItem: passwordField,
attribute: .Top, multiplier: 1.0, constant: -8)
// changed to -8
let constraintPasswordLabelHTrailing = NSLayoutConstraint(item: passwordLabel,
attribute: .Trailing, relatedBy: .Equal, toItem: passwordField,
attribute: .Leading, multiplier: 1.0, constant: -8)
class ViewController: UIViewController {
var label = UILabel()
var button = UIButton()
var stackView = UIStackView()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.cyan
navigationItem.title = "VCTitle"
setupUI()
}
private func setupUI(){
label.backgroundColor = UIColor.blue
label.heightAnchor.constraint(equalToConstant: 50).isActive = true
label.widthAnchor.constraint(equalToConstant: 80).isActive = true
button.backgroundColor = UIColor.purple
button.heightAnchor.constraint(equalToConstant: 30).isActive = true
button.widthAnchor.constraint(equalToConstant: 10).isActive = true
setupStackView()
stackView.addArrangedSubview(label)
stackView.addArrangedSubview(button)
stackView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(stackView) // AA
}
private func setupStackView(){
stackView.axis = UILayoutConstraintAxis.vertical
stackView.distribution = UIStackViewDistribution.equalSpacing
stackView.alignment = UIStackViewAlignment.center
stackView.spacing = 15
stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true // B1
stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true // B2
}
}
class ViewController: UIViewController {
var label = UILabel()
var button = UIButton()
var stackView = UIStackView()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.cyan
navigationItem.title = "VCTitle"
setupUI()
}
private func setupUI(){
label.backgroundColor = UIColor.blue
label.heightAnchor.constraint(equalToConstant: 50).isActive = true
label.widthAnchor.constraint(equalToConstant: 80).isActive = true
button.backgroundColor = UIColor.purple
button.heightAnchor.constraint(equalToConstant: 30).isActive = true
button.widthAnchor.constraint(equalToConstant: 10).isActive = true
setupStackView()
stackView.addArrangedSubview(label)
stackView.addArrangedSubview(button)
stackView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(stackView) //AA
// The 2 lines below are now in the right place.
stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true // B1
stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true // B2
}
private func setupStackView(){
stackView.axis = UILayoutConstraintAxis.vertical
stackView.distribution = UIStackViewDistribution.equalSpacing
stackView.alignment = UIStackViewAlignment.center
stackView.spacing = 15
}
}