iOS UIStackView 项目来包装内容,但分发项目以填充整个可用空间 space
iOS UIStackView items to wrap content but have the items distributed to fill entire available space
我有一个具有不同高度项目的 UIStackView。
项目的高度由它们的内容决定,我不想用约束来强制它。
我希望项目的间距始终占据整个可用屏幕。
我需要设置哪些设置才能使其正常工作?
这是一个非常简单的例子...
带有 3 个多行标签的垂直堆栈视图。每次我们点击任何地方,标签将是 re-filled 1 到 8 行文本,显示排列的子视图将确定自己的高度:
红色虚线矩形显示堆栈视图的框架。
示例代码如下:
class LenaBruViewController: UIViewController {
let stack: UIStackView = {
let v = UIStackView()
v.axis = .vertical
v.distribution = .equalSpacing
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
// add 3 labels to the stack view
for _ in 1...3 {
let v = UILabel()
v.numberOfLines = 0
// to make it easy to see the frames
v.backgroundColor = .yellow
stack.addArrangedSubview(v)
}
// red dashed-outline view to show the stack view frame
let stackOutlineView = DashedOutlineView()
[stackOutlineView, stack].forEach { v in
v.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(v)
}
// respect safe area
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// constrain stack view 20-pts from all 4 sides
stack.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
stack.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
stack.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
stack.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -20.0),
// constrain outline view 1-pt around the stack view
stackOutlineView.topAnchor.constraint(equalTo: stack.topAnchor, constant: -1.0),
stackOutlineView.leadingAnchor.constraint(equalTo: stack.leadingAnchor, constant: -1.0),
stackOutlineView.trailingAnchor.constraint(equalTo: stack.trailingAnchor, constant: 1.0),
stackOutlineView.bottomAnchor.constraint(equalTo: stack.bottomAnchor, constant: 1.0),
])
fillLabels()
// tap anywhere to re-fill the labels
let t = UITapGestureRecognizer(target: self, action: #selector(self.fillLabels))
view.addGestureRecognizer(t)
}
@objc func fillLabels() -> Void {
// set text of labels - from 1 to 8 lines
let a: [Int] = Array(1...8).shuffled()
for (v, n) in zip(stack.arrangedSubviews, a) {
guard let lbl = v as? UILabel else { fatalError("This Demo should have only labels in the stack view!!") }
lbl.text = ((1...n).map { "Line \([=10=])" }).joined(separator: "\n")
}
}
}
class DashedOutlineView: UIView {
var shapeLayer: CAShapeLayer!
override class var layerClass: AnyClass {
return CAShapeLayer.self
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() -> Void {
shapeLayer = self.layer as? CAShapeLayer
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = UIColor.red.cgColor
shapeLayer.lineWidth = 1.0
shapeLayer.lineDashPattern = [8,8]
}
override func layoutSubviews() {
super.layoutSubviews()
shapeLayer.path = UIBezierPath(rect: bounds).cgPath
}
}
我有一个具有不同高度项目的 UIStackView。 项目的高度由它们的内容决定,我不想用约束来强制它。
我希望项目的间距始终占据整个可用屏幕。
我需要设置哪些设置才能使其正常工作?
这是一个非常简单的例子...
带有 3 个多行标签的垂直堆栈视图。每次我们点击任何地方,标签将是 re-filled 1 到 8 行文本,显示排列的子视图将确定自己的高度:
红色虚线矩形显示堆栈视图的框架。
示例代码如下:
class LenaBruViewController: UIViewController {
let stack: UIStackView = {
let v = UIStackView()
v.axis = .vertical
v.distribution = .equalSpacing
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
// add 3 labels to the stack view
for _ in 1...3 {
let v = UILabel()
v.numberOfLines = 0
// to make it easy to see the frames
v.backgroundColor = .yellow
stack.addArrangedSubview(v)
}
// red dashed-outline view to show the stack view frame
let stackOutlineView = DashedOutlineView()
[stackOutlineView, stack].forEach { v in
v.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(v)
}
// respect safe area
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// constrain stack view 20-pts from all 4 sides
stack.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
stack.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
stack.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
stack.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -20.0),
// constrain outline view 1-pt around the stack view
stackOutlineView.topAnchor.constraint(equalTo: stack.topAnchor, constant: -1.0),
stackOutlineView.leadingAnchor.constraint(equalTo: stack.leadingAnchor, constant: -1.0),
stackOutlineView.trailingAnchor.constraint(equalTo: stack.trailingAnchor, constant: 1.0),
stackOutlineView.bottomAnchor.constraint(equalTo: stack.bottomAnchor, constant: 1.0),
])
fillLabels()
// tap anywhere to re-fill the labels
let t = UITapGestureRecognizer(target: self, action: #selector(self.fillLabels))
view.addGestureRecognizer(t)
}
@objc func fillLabels() -> Void {
// set text of labels - from 1 to 8 lines
let a: [Int] = Array(1...8).shuffled()
for (v, n) in zip(stack.arrangedSubviews, a) {
guard let lbl = v as? UILabel else { fatalError("This Demo should have only labels in the stack view!!") }
lbl.text = ((1...n).map { "Line \([=10=])" }).joined(separator: "\n")
}
}
}
class DashedOutlineView: UIView {
var shapeLayer: CAShapeLayer!
override class var layerClass: AnyClass {
return CAShapeLayer.self
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() -> Void {
shapeLayer = self.layer as? CAShapeLayer
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = UIColor.red.cgColor
shapeLayer.lineWidth = 1.0
shapeLayer.lineDashPattern = [8,8]
}
override func layoutSubviews() {
super.layoutSubviews()
shapeLayer.path = UIBezierPath(rect: bounds).cgPath
}
}