当框架小于所需时,为 UIStackView 中的第一个 UILabel 提供更高的优先级
Give more priority for the first UILabel in a UIStackView when frame is smaller than required
我有一个标签数组:[UILabel]
,计数是根据数组中元素的数量计算的。我通过循环将它们添加到 UIStackView
中。在某一点上,UILabel
s 的数量超过了 UIStackView
的帧,在这种情况下,我希望显示先添加的 UILabel
s,然后隐藏后添加的 UILabel
s。发生的事情恰恰相反。像这样:-
我希望 text 1
优先于 text 2
显示,依此类推。这是代码:
override func viewDidLoad() {
super.viewDidLoad()
let stackView = UIStackView()
stackView.alignment = .top
stackView.axis = .vertical
view.addSubview(stackView)
stackView.center = view.center
stackView.frame.size = CGSize(width: 100, height: 24)
(0..<4).forEach {
let label = UILabel()
label.text = "text \([=10=])"
label.backgroundColor = .red
stackView.addArrangedSubview(label)
}
}
仅供参考:我不想颠倒订单。
更新:感谢@DonMag 和@Rob,我在我的代码中设置了内容抗压缩优先级。不幸的是,出于某种原因,我得到的结果与@DonMag 在他的屏幕截图中描述的结果不同。这是我更新的代码:
override func viewDidLoad() {
super.viewDidLoad()
let stackView = UIStackView()
stackView.alignment = .leading
stackView.axis = .vertical
view.addSubview(stackView)
stackView.frame = CGRect(x: 100, y: 100, width: 100, height: 150)
(0..<15).forEach {
let label = UILabel()
label.text = "text \([=11=])"
label.backgroundColor = .red
stackView.addArrangedSubview(label)
}
var p: Float = 1000
for v in stackView.arrangedSubviews {
v.setContentCompressionResistancePriority(UILayoutPriority(rawValue: p), for: .vertical)
p -= 1
}
}
这就是我所说的结果:
应该这样做:
var p: Float = 1000
for v in stackView.arrangedSubviews {
v.setContentCompressionResistancePriority(UILayoutPriority(rawValue: p), for: .vertical)
p -= 1
}
虽然使用堆栈视图的方式有点奇怪,但它可能无法满足您的需求。
例如,使用 100 x 150
帧和 14 个标签,我们得到:
如我们所见,底部标签有点“偏离”。
而且,只有 5 个标签,我们得到:
顶部标签的高度会被拉伸,除非我们对 Content Hugging 优先级做同样的事情...在这种情况下底部标签会被拉伸。
更好的方法是将堆栈视图嵌入 UIView
,约束 Top / Leading / Trailing,设置“容器”的高度 UIView
,然后确保设置.clipsToBounds = true
在容器视图上。
有 14 个标签:
有 5 个标签:
这是要玩的代码...
方法一:
class FrankMethod1ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let stackView = UIStackView()
stackView.alignment = .leading
stackView.axis = .vertical
view.addSubview(stackView)
stackView.frame = CGRect(x: 100, y: 100, width: 100, height: 150)
// change to (0..<5) to see the stretching
(0..<15).forEach {
let label = UILabel()
label.text = "text \([=11=])"
label.backgroundColor = .red
stackView.addArrangedSubview(label)
}
var p: Float = 1000
for v in stackView.arrangedSubviews {
v.setContentCompressionResistancePriority(UILayoutPriority(rawValue: p), for: .vertical)
p -= 1
}
}
}
方法二:
class FrankMethod2ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let cView = UIView()
cView.frame = CGRect(x: 100, y: 100, width: 100, height: 150)
cView.clipsToBounds = true
// so we can see the view frame
cView.backgroundColor = .cyan
view.addSubview(cView)
let stackView = UIStackView()
stackView.alignment = .leading
stackView.axis = .vertical
cView.addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: cView.topAnchor),
stackView.leadingAnchor.constraint(equalTo: cView.leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: cView.trailingAnchor),
])
// change to (0..<5) to see NO stretching
(0..<15).forEach {
let label = UILabel()
label.text = "text \([=12=])"
label.backgroundColor = .red
stackView.addArrangedSubview(label)
}
}
}
编辑
我认为 Playground 执行与 Sim/Device 之间存在差异并不罕见。
这是我得到的:
当 运行 此代码在 Playground 中时...前两个是带有 15 和 5 个标签的“方法 1”,后两个是带有 15 和 5 个标签的“方法 2”:
import UIKit
import PlaygroundSupport
class PlaygroundFrankViewController: UIViewController {
override func loadView() {
let view = UIView()
view.backgroundColor = .white
self.view = view
}
override func viewDidLoad() {
super.viewDidLoad()
let stackView1 = UIStackView()
stackView1.alignment = .leading
stackView1.axis = .vertical
view.addSubview(stackView1)
stackView1.frame = CGRect(x: 50, y: 50, width: 100, height: 150)
// change to (0..<5) to see the stretching
(0..<15).forEach {
let label = UILabel()
label.text = "text \([=13=])"
label.backgroundColor = .red
stackView1.addArrangedSubview(label)
}
var p: Float = 1000
for v in stackView1.arrangedSubviews {
v.setContentCompressionResistancePriority(UILayoutPriority(rawValue: p), for: .vertical)
p -= 1
}
let stackView2 = UIStackView()
stackView2.alignment = .leading
stackView2.axis = .vertical
view.addSubview(stackView2)
stackView2.frame = CGRect(x: 200, y: 50, width: 100, height: 150)
// change to (0..<5) to see the stretching
(0..<5).forEach {
let label = UILabel()
label.text = "text \([=13=])"
label.backgroundColor = .red
stackView2.addArrangedSubview(label)
}
p = 1000
for v in stackView2.arrangedSubviews {
v.setContentCompressionResistancePriority(UILayoutPriority(rawValue: p), for: .vertical)
p -= 1
}
let cView1 = UIView()
cView1.frame = CGRect(x: 50, y: 220, width: 100, height: 150)
cView1.clipsToBounds = true
// so we can see the view frame
cView1.backgroundColor = .cyan
view.addSubview(cView1)
let stackView3 = UIStackView()
stackView3.alignment = .leading
stackView3.axis = .vertical
cView1.addSubview(stackView3)
stackView3.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
stackView3.topAnchor.constraint(equalTo: cView1.topAnchor),
stackView3.leadingAnchor.constraint(equalTo: cView1.leadingAnchor),
stackView3.trailingAnchor.constraint(equalTo: cView1.trailingAnchor),
])
// change to (0..<5) to see NO stretching
(0..<15).forEach {
let label = UILabel()
label.text = "text \([=13=])"
label.backgroundColor = .red
stackView3.addArrangedSubview(label)
}
let cView2 = UIView()
cView2.frame = CGRect(x: 200, y: 220, width: 100, height: 150)
cView2.clipsToBounds = true
// so we can see the view frame
cView2.backgroundColor = .cyan
view.addSubview(cView2)
let stackView4 = UIStackView()
stackView4.alignment = .leading
stackView4.axis = .vertical
cView2.addSubview(stackView4)
stackView4.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
stackView4.topAnchor.constraint(equalTo: cView2.topAnchor),
stackView4.leadingAnchor.constraint(equalTo: cView2.leadingAnchor),
stackView4.trailingAnchor.constraint(equalTo: cView2.trailingAnchor),
])
// change to (0..<5) to see NO stretching
(0..<5).forEach {
let label = UILabel()
label.text = "text \([=13=])"
label.backgroundColor = .red
stackView4.addArrangedSubview(label)
}
}
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = PlaygroundFrankViewController()
我有一个标签数组:[UILabel]
,计数是根据数组中元素的数量计算的。我通过循环将它们添加到 UIStackView
中。在某一点上,UILabel
s 的数量超过了 UIStackView
的帧,在这种情况下,我希望显示先添加的 UILabel
s,然后隐藏后添加的 UILabel
s。发生的事情恰恰相反。像这样:-
我希望 text 1
优先于 text 2
显示,依此类推。这是代码:
override func viewDidLoad() {
super.viewDidLoad()
let stackView = UIStackView()
stackView.alignment = .top
stackView.axis = .vertical
view.addSubview(stackView)
stackView.center = view.center
stackView.frame.size = CGSize(width: 100, height: 24)
(0..<4).forEach {
let label = UILabel()
label.text = "text \([=10=])"
label.backgroundColor = .red
stackView.addArrangedSubview(label)
}
}
仅供参考:我不想颠倒订单。
更新:感谢@DonMag 和@Rob,我在我的代码中设置了内容抗压缩优先级。不幸的是,出于某种原因,我得到的结果与@DonMag 在他的屏幕截图中描述的结果不同。这是我更新的代码:
override func viewDidLoad() {
super.viewDidLoad()
let stackView = UIStackView()
stackView.alignment = .leading
stackView.axis = .vertical
view.addSubview(stackView)
stackView.frame = CGRect(x: 100, y: 100, width: 100, height: 150)
(0..<15).forEach {
let label = UILabel()
label.text = "text \([=11=])"
label.backgroundColor = .red
stackView.addArrangedSubview(label)
}
var p: Float = 1000
for v in stackView.arrangedSubviews {
v.setContentCompressionResistancePriority(UILayoutPriority(rawValue: p), for: .vertical)
p -= 1
}
}
这就是我所说的结果:
应该这样做:
var p: Float = 1000
for v in stackView.arrangedSubviews {
v.setContentCompressionResistancePriority(UILayoutPriority(rawValue: p), for: .vertical)
p -= 1
}
虽然使用堆栈视图的方式有点奇怪,但它可能无法满足您的需求。
例如,使用 100 x 150
帧和 14 个标签,我们得到:
如我们所见,底部标签有点“偏离”。
而且,只有 5 个标签,我们得到:
顶部标签的高度会被拉伸,除非我们对 Content Hugging 优先级做同样的事情...在这种情况下底部标签会被拉伸。
更好的方法是将堆栈视图嵌入 UIView
,约束 Top / Leading / Trailing,设置“容器”的高度 UIView
,然后确保设置.clipsToBounds = true
在容器视图上。
有 14 个标签:
有 5 个标签:
这是要玩的代码...
方法一:
class FrankMethod1ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let stackView = UIStackView()
stackView.alignment = .leading
stackView.axis = .vertical
view.addSubview(stackView)
stackView.frame = CGRect(x: 100, y: 100, width: 100, height: 150)
// change to (0..<5) to see the stretching
(0..<15).forEach {
let label = UILabel()
label.text = "text \([=11=])"
label.backgroundColor = .red
stackView.addArrangedSubview(label)
}
var p: Float = 1000
for v in stackView.arrangedSubviews {
v.setContentCompressionResistancePriority(UILayoutPriority(rawValue: p), for: .vertical)
p -= 1
}
}
}
方法二:
class FrankMethod2ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let cView = UIView()
cView.frame = CGRect(x: 100, y: 100, width: 100, height: 150)
cView.clipsToBounds = true
// so we can see the view frame
cView.backgroundColor = .cyan
view.addSubview(cView)
let stackView = UIStackView()
stackView.alignment = .leading
stackView.axis = .vertical
cView.addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: cView.topAnchor),
stackView.leadingAnchor.constraint(equalTo: cView.leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: cView.trailingAnchor),
])
// change to (0..<5) to see NO stretching
(0..<15).forEach {
let label = UILabel()
label.text = "text \([=12=])"
label.backgroundColor = .red
stackView.addArrangedSubview(label)
}
}
}
编辑
我认为 Playground 执行与 Sim/Device 之间存在差异并不罕见。
这是我得到的:
当 运行 此代码在 Playground 中时...前两个是带有 15 和 5 个标签的“方法 1”,后两个是带有 15 和 5 个标签的“方法 2”:
import UIKit
import PlaygroundSupport
class PlaygroundFrankViewController: UIViewController {
override func loadView() {
let view = UIView()
view.backgroundColor = .white
self.view = view
}
override func viewDidLoad() {
super.viewDidLoad()
let stackView1 = UIStackView()
stackView1.alignment = .leading
stackView1.axis = .vertical
view.addSubview(stackView1)
stackView1.frame = CGRect(x: 50, y: 50, width: 100, height: 150)
// change to (0..<5) to see the stretching
(0..<15).forEach {
let label = UILabel()
label.text = "text \([=13=])"
label.backgroundColor = .red
stackView1.addArrangedSubview(label)
}
var p: Float = 1000
for v in stackView1.arrangedSubviews {
v.setContentCompressionResistancePriority(UILayoutPriority(rawValue: p), for: .vertical)
p -= 1
}
let stackView2 = UIStackView()
stackView2.alignment = .leading
stackView2.axis = .vertical
view.addSubview(stackView2)
stackView2.frame = CGRect(x: 200, y: 50, width: 100, height: 150)
// change to (0..<5) to see the stretching
(0..<5).forEach {
let label = UILabel()
label.text = "text \([=13=])"
label.backgroundColor = .red
stackView2.addArrangedSubview(label)
}
p = 1000
for v in stackView2.arrangedSubviews {
v.setContentCompressionResistancePriority(UILayoutPriority(rawValue: p), for: .vertical)
p -= 1
}
let cView1 = UIView()
cView1.frame = CGRect(x: 50, y: 220, width: 100, height: 150)
cView1.clipsToBounds = true
// so we can see the view frame
cView1.backgroundColor = .cyan
view.addSubview(cView1)
let stackView3 = UIStackView()
stackView3.alignment = .leading
stackView3.axis = .vertical
cView1.addSubview(stackView3)
stackView3.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
stackView3.topAnchor.constraint(equalTo: cView1.topAnchor),
stackView3.leadingAnchor.constraint(equalTo: cView1.leadingAnchor),
stackView3.trailingAnchor.constraint(equalTo: cView1.trailingAnchor),
])
// change to (0..<5) to see NO stretching
(0..<15).forEach {
let label = UILabel()
label.text = "text \([=13=])"
label.backgroundColor = .red
stackView3.addArrangedSubview(label)
}
let cView2 = UIView()
cView2.frame = CGRect(x: 200, y: 220, width: 100, height: 150)
cView2.clipsToBounds = true
// so we can see the view frame
cView2.backgroundColor = .cyan
view.addSubview(cView2)
let stackView4 = UIStackView()
stackView4.alignment = .leading
stackView4.axis = .vertical
cView2.addSubview(stackView4)
stackView4.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
stackView4.topAnchor.constraint(equalTo: cView2.topAnchor),
stackView4.leadingAnchor.constraint(equalTo: cView2.leadingAnchor),
stackView4.trailingAnchor.constraint(equalTo: cView2.trailingAnchor),
])
// change to (0..<5) to see NO stretching
(0..<5).forEach {
let label = UILabel()
label.text = "text \([=13=])"
label.backgroundColor = .red
stackView4.addArrangedSubview(label)
}
}
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = PlaygroundFrankViewController()