Swift 以编程方式添加约束不起作用
Swift programmatically-added constraints dont work
我在滚动视图中有一个视图:
现在我想以编程方式将子视图添加到该视图。这就是我的代码:
儿童视角(有效)
//Adds header to the view again because it was removed in the clear() method
//Header is just a label
lv.addSubview(header)
header.leadingAnchor.constraint(equalTo: header.superview!.leadingAnchor).isActive = true
header.topAnchor.constraint(equalTo: header.superview!.topAnchor, constant: 2).isActive = true
header.widthAnchor.constraint(equalTo: header.superview!.widthAnchor).isActive = true
header.heightAnchor.constraint(equalToConstant: MainTabViewController.fontSize*3).isActive = true //Just a constant
现在我重复执行这段代码:
private func makeTextLabel(text: NSAttributedString, bgColor: UIColor?, maxWidth: CGFloat?) -> UILabel {
//Creates label
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
lv.addSubview(label)
//Adjustments
if(bgColor != nil) {
label.backgroundColor = bgColor
}
label.textColor = UIColor.black
label.attributedText = text
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byWordWrapping
let width = maxWidth ?? lv.frame.size.width-8
label.widthAnchor.constraint(equalToConstant: width).isActive = true
label.heightAnchor.constraint(equalToConstant: heightForLabel(attributedText: label.attributedText, width: width)).isActive = true
label.leadingAnchor.constraint(equalTo: lv.leadingAnchor, constant: 4).isActive = true
let previousView = lv.subviews[lv.subviews.count-1]
label.topAnchor.constraint(equalTo: previousView.bottomAnchor, constant: 10).isActive = true
return label
}
添加了所有标签,但约束根本不起作用。这是它的样子(当我执行上面的方法 2 次时):
编辑:主要问题已解决。我现在正在使用 StackView。()
我现在想让我的标签有一个边缘偏移,所以我使用这些线:
label.leadingAnchor.constraint(equalTo: lessonStackView.leadingAnchor, constant: offset).isActive = true
label.trailingAnchor.constraint(equalTo: lessonStackView.trailingAnchor, constant: -offset).isActive = true
但是由于 StackView 似乎自己设置了 x 约束,我收到了这个警告:
无法同时满足约束条件。
可能至少以下列表中的约束之一是您不想要的。
试试这个:
(1)查看每个约束并尝试找出您不期望的;
(2) 找到添加了不需要的约束或约束的代码并修复它。
(
"UILabel:0x7f9c16c22c30'Falls dir die App gef\U00e4llt...' (active, names: '|':JavaProf.MultipleContentsView:0x7f9c19024a60 )>",
"",
“”
)
将尝试通过打破约束来恢复
我该如何解决?
删除 width
锚点。你不应该关心宽度(你真的不知道),使用 trailingAnchor
代替:
label.trailingAnchor.constraint(equalTo: lv.trailingAnchor, constant: -4).isActive = true
删除heightAnchor
,让系统为您计算身高:
label.setContentHuggingPriority(.required, for: .vertical)
label.setContentCompressionResistancePriority(.required, for: .vertical)
这应该是所有需要的。
但是,作为旁注,您可以只使用 UIStackView
.
而不是对先前的标签创建约束
如果你想对一堆标签(或其他视图)使用 UIStackView
并且你希望它们有不同的前导间距,你有几个选择:
1) 将标签嵌入UIView
。让UIView
填满stack view的宽度,并将包含的标签约束给view。
2) 将堆栈视图 Aligment
设置为 Trailing
。然后为每个标签添加一个宽度约束,等于堆栈视图的宽度。对于您想要的标签,比如说,一个 32 点的 "left margin," 将该标签上的常量设置为 -32
.
这是一个简单的例子:
class LeftMarginViewController: UIViewController {
let stackView: UIStackView = {
let v = UIStackView()
v.axis = .vertical
v.alignment = .trailing
v.distribution = .fill
v.spacing = 8
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
for i in 1...7 {
let v = UILabel()
v.backgroundColor = .yellow
v.numberOfLines = 0
if i == 5 {
v.text = "Label 5 has a lot of text to demonstrate what happens when it needs to wrap onto multiple lines."
} else {
v.text = "Label \(i)"
}
stackView.addArrangedSubview(v)
switch i {
case 6:
v.widthAnchor.constraint(equalTo: stackView.widthAnchor, multiplier: 1.0, constant: -32.0).isActive = true
case 2, 4, 5:
v.widthAnchor.constraint(equalTo: stackView.widthAnchor, multiplier: 1.0, constant: -16.0).isActive = true
default:
v.widthAnchor.constraint(equalTo: stackView.widthAnchor, multiplier: 1.0, constant: 0.0).isActive = true
}
}
stackView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(stackView)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: g.topAnchor, constant: 40.0),
stackView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 40.0),
stackView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -40.0),
])
}
}
堆栈视图有 Alignment: Trailing
,每个标签的宽度等于堆栈视图宽度,标签 2、4 和 5 有 constant = -16
,标签 6 有 constant = -32
.
结果:
我在滚动视图中有一个视图:
现在我想以编程方式将子视图添加到该视图。这就是我的代码:
儿童视角(有效)
//Adds header to the view again because it was removed in the clear() method //Header is just a label lv.addSubview(header) header.leadingAnchor.constraint(equalTo: header.superview!.leadingAnchor).isActive = true header.topAnchor.constraint(equalTo: header.superview!.topAnchor, constant: 2).isActive = true header.widthAnchor.constraint(equalTo: header.superview!.widthAnchor).isActive = true header.heightAnchor.constraint(equalToConstant: MainTabViewController.fontSize*3).isActive = true //Just a constant
现在我重复执行这段代码:
private func makeTextLabel(text: NSAttributedString, bgColor: UIColor?, maxWidth: CGFloat?) -> UILabel {
//Creates label
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
lv.addSubview(label)
//Adjustments
if(bgColor != nil) {
label.backgroundColor = bgColor
}
label.textColor = UIColor.black
label.attributedText = text
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byWordWrapping
let width = maxWidth ?? lv.frame.size.width-8
label.widthAnchor.constraint(equalToConstant: width).isActive = true
label.heightAnchor.constraint(equalToConstant: heightForLabel(attributedText: label.attributedText, width: width)).isActive = true
label.leadingAnchor.constraint(equalTo: lv.leadingAnchor, constant: 4).isActive = true
let previousView = lv.subviews[lv.subviews.count-1]
label.topAnchor.constraint(equalTo: previousView.bottomAnchor, constant: 10).isActive = true
return label
}
添加了所有标签,但约束根本不起作用。这是它的样子(当我执行上面的方法 2 次时):
编辑:主要问题已解决。我现在正在使用 StackView。(
我现在想让我的标签有一个边缘偏移,所以我使用这些线:
label.leadingAnchor.constraint(equalTo: lessonStackView.leadingAnchor, constant: offset).isActive = true
label.trailingAnchor.constraint(equalTo: lessonStackView.trailingAnchor, constant: -offset).isActive = true
但是由于 StackView 似乎自己设置了 x 约束,我收到了这个警告:
无法同时满足约束条件。 可能至少以下列表中的约束之一是您不想要的。 试试这个: (1)查看每个约束并尝试找出您不期望的; (2) 找到添加了不需要的约束或约束的代码并修复它。 ( "UILabel:0x7f9c16c22c30'Falls dir die App gef\U00e4llt...' (active, names: '|':JavaProf.MultipleContentsView:0x7f9c19024a60 )>", "", “” )
将尝试通过打破约束来恢复
我该如何解决?
删除 width
锚点。你不应该关心宽度(你真的不知道),使用 trailingAnchor
代替:
label.trailingAnchor.constraint(equalTo: lv.trailingAnchor, constant: -4).isActive = true
删除heightAnchor
,让系统为您计算身高:
label.setContentHuggingPriority(.required, for: .vertical)
label.setContentCompressionResistancePriority(.required, for: .vertical)
这应该是所有需要的。
但是,作为旁注,您可以只使用 UIStackView
.
如果你想对一堆标签(或其他视图)使用 UIStackView
并且你希望它们有不同的前导间距,你有几个选择:
1) 将标签嵌入UIView
。让UIView
填满stack view的宽度,并将包含的标签约束给view。
2) 将堆栈视图 Aligment
设置为 Trailing
。然后为每个标签添加一个宽度约束,等于堆栈视图的宽度。对于您想要的标签,比如说,一个 32 点的 "left margin," 将该标签上的常量设置为 -32
.
这是一个简单的例子:
class LeftMarginViewController: UIViewController {
let stackView: UIStackView = {
let v = UIStackView()
v.axis = .vertical
v.alignment = .trailing
v.distribution = .fill
v.spacing = 8
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
for i in 1...7 {
let v = UILabel()
v.backgroundColor = .yellow
v.numberOfLines = 0
if i == 5 {
v.text = "Label 5 has a lot of text to demonstrate what happens when it needs to wrap onto multiple lines."
} else {
v.text = "Label \(i)"
}
stackView.addArrangedSubview(v)
switch i {
case 6:
v.widthAnchor.constraint(equalTo: stackView.widthAnchor, multiplier: 1.0, constant: -32.0).isActive = true
case 2, 4, 5:
v.widthAnchor.constraint(equalTo: stackView.widthAnchor, multiplier: 1.0, constant: -16.0).isActive = true
default:
v.widthAnchor.constraint(equalTo: stackView.widthAnchor, multiplier: 1.0, constant: 0.0).isActive = true
}
}
stackView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(stackView)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: g.topAnchor, constant: 40.0),
stackView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 40.0),
stackView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -40.0),
])
}
}
堆栈视图有 Alignment: Trailing
,每个标签的宽度等于堆栈视图宽度,标签 2、4 和 5 有 constant = -16
,标签 6 有 constant = -32
.
结果: