如何通过优先级改变内在内容的大小
How to change the intrinsic content size through its priority
我希望第二个标签 (subview2
) 保持原样并让第一个标签 (subview1
) 随着容器视图尺寸的减小而缩小,但第二个标签仍然不管我怎么调整优先级都缩水:
import UIKit
import PlaygroundSupport
let containerView = UIView(frame: CGRect(origin: .zero, size: .init(width: 200, height: 300)))
let subview1 = UILabel()
subview1.text = "Hello"
subview1.backgroundColor = .red
containerView.addSubview(subview1)
subview1.translatesAutoresizingMaskIntoConstraints = false
let subview2 = UILabel()
subview2.text = "Hello"
subview2.backgroundColor = .cyan
containerView.addSubview(subview2)
subview2.translatesAutoresizingMaskIntoConstraints = false
let views: [String: Any] = ["subview1": subview1, "subview2": subview2]
let con1 = NSLayoutConstraint.constraints(withVisualFormat: "V:|-(20)-[subview1]", metrics: nil, views: views)
let con2 = NSLayoutConstraint.constraints(withVisualFormat: "V:|-(20)-[subview2]", metrics: nil, views: views)
let con3 = NSLayoutConstraint.constraints(withVisualFormat: "H:|-(30)-[subview1]", metrics: nil, views: views)
let con4 = NSLayoutConstraint.constraints(withVisualFormat: "H:[subview2]-(30)-|", metrics: nil, views: views)
let con5 = NSLayoutConstraint.constraints(withVisualFormat: "H:[subview1(>=100)]-(>=30)-[subview2(>=100)]", metrics: nil, views: views)
NSLayoutConstraint.activate(con1 + con2 + con3 + con4 + con5)
subview1.setContentCompressionResistancePriority(UILayoutPriority.defaultLow, for: .horizontal)
subview2.setContentCompressionResistancePriority(UILayoutPriority.defaultHigh, for: .horizontal)
PlaygroundPage.current.needsIndefiniteExecution = true
PlaygroundPage.current.liveView = containerView
我试过手动增加 subview2
的优先级,但还是没用:
let priority1 = subview2.contentCompressionResistancePriority(for: .horizontal)
print(priority1) // 750
let priority2 = subview2.contentCompressionResistancePriority(for: .horizontal)
print(priority2) // 750
subview2.setContentCompressionResistancePriority(priority2 + 100, for: .horizontal)
VFL(视觉格式语言)非常过时且受限。我强烈建议您改用更现代(也更灵活)的语法。
也就是说,问题出在这一行:
let con5 = NSLayoutConstraint.constraints(withVisualFormat:
"H:[subview1(>=100)]-(>=30)-[subview2(>=100)]", metrics: nil, views: views)
您的代码表示:
subview1
宽度必须大于等于100
subview2
宽度必须大于等于100
所以,setContentCompressionResistancePriority
行什么都不做。您已经说过“这些是 要求的 最小宽度。”
如果将该行更改为:
let con5 = NSLayoutConstraint.constraints(withVisualFormat:
"H:[subview1]-(>=30)-[subview2]", metrics: nil, views: views)
您应该会得到想要的结果。
不过,您的代码使用了更现代的约束语法——您可能会发现它更合乎逻辑且更容易理解:
NSLayoutConstraint.activate([
// both labels 20-pts from containerView Top
subview1.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 20.0),
subview2.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 20.0),
// left label Leading 30-pts from containerView Leading
subview1.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 30.0),
// right label Trailing 30-pts from containerView Trailing
subview2.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -30.0),
// right label Leading at least 30-pts from left label Trailing
subview2.leadingAnchor.constraint(greaterThanOrEqualTo: subview1.trailingAnchor, constant: 30.0),
])
// don't do any of this...
//let views: [String: Any] = ["subview1": subview1, "subview2": subview2]
//let con1 = NSLayoutConstraint.constraints(withVisualFormat: "V:|-(20)-[subview1]", metrics: nil, views: views)
//let con2 = NSLayoutConstraint.constraints(withVisualFormat: "V:|-(20)-[subview2]", metrics: nil, views: views)
//let con3 = NSLayoutConstraint.constraints(withVisualFormat: "H:|-(30)-[subview1]", metrics: nil, views: views)
//let con4 = NSLayoutConstraint.constraints(withVisualFormat: "H:[subview2]-(30)-|", metrics: nil, views: views)
//let con5 = NSLayoutConstraint.constraints(withVisualFormat: "H:[subview1]-(>=30)-[subview2]", metrics: nil, views: views)
//NSLayoutConstraint.activate(con1 + con2 + con3 + con4 + con5)
编辑 - 回复评论...
如果您希望每个标签的宽度都为 >= 100
,但允许它们压缩(首先压缩左标签),则需要添加优先级小于 [=20 的宽度约束=]:
// both labels should have a width of >= 100
let leftWidth = subview1.widthAnchor.constraint(greaterThanOrEqualToConstant: 100.0)
let rightWidth = subview2.widthAnchor.constraint(greaterThanOrEqualToConstant: 100.0)
// set the Priority on the width constraints to less than required
// to allow auto-layout to break that constraint if needed
leftWidth.priority = .defaultHigh
rightWidth.priority = .defaultHigh
// activate the width constraints
leftWidth.isActive = true
rightWidth.isActive = true
// tell leftLabel to compress before rightLabel
subview1.setContentCompressionResistancePriority(UILayoutPriority.defaultLow, for: .horizontal)
subview2.setContentCompressionResistancePriority(UILayoutPriority.defaultHigh, for: .horizontal)
我希望第二个标签 (subview2
) 保持原样并让第一个标签 (subview1
) 随着容器视图尺寸的减小而缩小,但第二个标签仍然不管我怎么调整优先级都缩水:
import UIKit
import PlaygroundSupport
let containerView = UIView(frame: CGRect(origin: .zero, size: .init(width: 200, height: 300)))
let subview1 = UILabel()
subview1.text = "Hello"
subview1.backgroundColor = .red
containerView.addSubview(subview1)
subview1.translatesAutoresizingMaskIntoConstraints = false
let subview2 = UILabel()
subview2.text = "Hello"
subview2.backgroundColor = .cyan
containerView.addSubview(subview2)
subview2.translatesAutoresizingMaskIntoConstraints = false
let views: [String: Any] = ["subview1": subview1, "subview2": subview2]
let con1 = NSLayoutConstraint.constraints(withVisualFormat: "V:|-(20)-[subview1]", metrics: nil, views: views)
let con2 = NSLayoutConstraint.constraints(withVisualFormat: "V:|-(20)-[subview2]", metrics: nil, views: views)
let con3 = NSLayoutConstraint.constraints(withVisualFormat: "H:|-(30)-[subview1]", metrics: nil, views: views)
let con4 = NSLayoutConstraint.constraints(withVisualFormat: "H:[subview2]-(30)-|", metrics: nil, views: views)
let con5 = NSLayoutConstraint.constraints(withVisualFormat: "H:[subview1(>=100)]-(>=30)-[subview2(>=100)]", metrics: nil, views: views)
NSLayoutConstraint.activate(con1 + con2 + con3 + con4 + con5)
subview1.setContentCompressionResistancePriority(UILayoutPriority.defaultLow, for: .horizontal)
subview2.setContentCompressionResistancePriority(UILayoutPriority.defaultHigh, for: .horizontal)
PlaygroundPage.current.needsIndefiniteExecution = true
PlaygroundPage.current.liveView = containerView
我试过手动增加 subview2
的优先级,但还是没用:
let priority1 = subview2.contentCompressionResistancePriority(for: .horizontal)
print(priority1) // 750
let priority2 = subview2.contentCompressionResistancePriority(for: .horizontal)
print(priority2) // 750
subview2.setContentCompressionResistancePriority(priority2 + 100, for: .horizontal)
VFL(视觉格式语言)非常过时且受限。我强烈建议您改用更现代(也更灵活)的语法。
也就是说,问题出在这一行:
let con5 = NSLayoutConstraint.constraints(withVisualFormat:
"H:[subview1(>=100)]-(>=30)-[subview2(>=100)]", metrics: nil, views: views)
您的代码表示:
subview1
宽度必须大于等于100
subview2
宽度必须大于等于100
所以,setContentCompressionResistancePriority
行什么都不做。您已经说过“这些是 要求的 最小宽度。”
如果将该行更改为:
let con5 = NSLayoutConstraint.constraints(withVisualFormat:
"H:[subview1]-(>=30)-[subview2]", metrics: nil, views: views)
您应该会得到想要的结果。
不过,您的代码使用了更现代的约束语法——您可能会发现它更合乎逻辑且更容易理解:
NSLayoutConstraint.activate([
// both labels 20-pts from containerView Top
subview1.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 20.0),
subview2.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 20.0),
// left label Leading 30-pts from containerView Leading
subview1.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 30.0),
// right label Trailing 30-pts from containerView Trailing
subview2.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -30.0),
// right label Leading at least 30-pts from left label Trailing
subview2.leadingAnchor.constraint(greaterThanOrEqualTo: subview1.trailingAnchor, constant: 30.0),
])
// don't do any of this...
//let views: [String: Any] = ["subview1": subview1, "subview2": subview2]
//let con1 = NSLayoutConstraint.constraints(withVisualFormat: "V:|-(20)-[subview1]", metrics: nil, views: views)
//let con2 = NSLayoutConstraint.constraints(withVisualFormat: "V:|-(20)-[subview2]", metrics: nil, views: views)
//let con3 = NSLayoutConstraint.constraints(withVisualFormat: "H:|-(30)-[subview1]", metrics: nil, views: views)
//let con4 = NSLayoutConstraint.constraints(withVisualFormat: "H:[subview2]-(30)-|", metrics: nil, views: views)
//let con5 = NSLayoutConstraint.constraints(withVisualFormat: "H:[subview1]-(>=30)-[subview2]", metrics: nil, views: views)
//NSLayoutConstraint.activate(con1 + con2 + con3 + con4 + con5)
编辑 - 回复评论...
如果您希望每个标签的宽度都为 >= 100
,但允许它们压缩(首先压缩左标签),则需要添加优先级小于 [=20 的宽度约束=]:
// both labels should have a width of >= 100
let leftWidth = subview1.widthAnchor.constraint(greaterThanOrEqualToConstant: 100.0)
let rightWidth = subview2.widthAnchor.constraint(greaterThanOrEqualToConstant: 100.0)
// set the Priority on the width constraints to less than required
// to allow auto-layout to break that constraint if needed
leftWidth.priority = .defaultHigh
rightWidth.priority = .defaultHigh
// activate the width constraints
leftWidth.isActive = true
rightWidth.isActive = true
// tell leftLabel to compress before rightLabel
subview1.setContentCompressionResistancePriority(UILayoutPriority.defaultLow, for: .horizontal)
subview2.setContentCompressionResistancePriority(UILayoutPriority.defaultHigh, for: .horizontal)