UIStackView 等间距包括边缘
UIStackView equal spacing including edges
我有一个带有 3 个按钮的水平堆栈视图:音乐应用程序的后退、播放、前进。
这是我当前的代码:
self.controlStackView.axis = .horizontal
self.controlStackView.distribution = .equalSpacing
self.controlStackView.alignment = .center
self.controlStackView.spacing = 10.0
self.controlStackView.translatesAutoresizingMaskIntoConstraints = false
self.contentView.addSubview(self.controlStackView)
self.controlStackView.topAnchor.constraint(equalTo: self.artworkImageView.bottomAnchor, constant: 10.0).isActive = true
self.controlStackView.centerXAnchor.constraint(equalTo: self.contentView.centerXAnchor).isActive = true
这是什么,它按如下方式分布按钮(由于对齐从中心开始):
[backward] - 10 spacing - [play] - 10 spacing - [forward]
我可以增加间距,但它仍然是固定的。
所以我设置了前导和尾随锚点来定义堆栈视图的最大宽度:
self.controlStackView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
self.controlStackView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
这对布局有何影响:
[left edge backward] - lots of spaaaaaaace - [centered play] - lots of spaaaaaaace - [right edge forward]
它分布在整个宽度上(并且中心向左和向右之间有一个.equalSpacing)。但这也无济于事。本质上,我的目标是拥有真正相等的间距,包括边缘。
假设我的可用宽度为 100,我的 3 个按钮分别为 10、20、10 - 这意味着还剩下 60 个 space 是空的。
我希望这样分发:
space - [backward] - space - [play] - space [forward] - space
所以我的按钮之间有 4 spaces,每个 space 是 15,所以我们填充剩余的 60 个 space。
我当然可以对堆栈视图实施填充以获得外部 space,但这将是相当静态的并且分布不均。
有谁知道我是否可以通过这种方式将边缘包含在 space 分布中?
谢谢
这真的很简单,使用 "spacer" 视图。
比按钮的数量多一个垫片,所以你有:
spacer - button - spacer - button - spacer
然后,将间隔物的宽度限制为 2 到 n 等于第一个间隔物的宽度。 stackView 将处理其余部分!
这里是一个例子(只需要一个viewController在storyboard中,其余的通过代码完成):
class DistributeViewController: UIViewController {
let stackView: UIStackView = {
let v = UIStackView()
v.translatesAutoresizingMaskIntoConstraints = false
v.axis = .horizontal
v.alignment = .fill
v.distribution = .fill
v.spacing = 0
return v
}()
var buttonTitles = [
"Backward",
"Play",
"Forward",
// "Next",
]
var numButtons = 0
override func viewDidLoad() {
super.viewDidLoad()
// stackView will hold the buttons and spacers
view.addSubview(stackView)
// constrain it to Top + 20, Leading and Trailing == 0, height will be controlled by button height
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20.0),
stackView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 0.0),
stackView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: 0.0),
])
// arrays to hold our buttons and spacers
var buttons: [UIView] = [UIView]()
var spacers: [UIView] = [UIView]()
numButtons = buttonTitles.count
// create the buttons and append them to our buttons array
for i in 0..<numButtons {
let b = UIButton()
b.translatesAutoresizingMaskIntoConstraints = false
b.backgroundColor = .blue
b.setTitle(buttonTitles[i], for: .normal)
buttons.append(b)
}
// create the spacer views and append them to our spacers array
// we need 1 more spacer than buttons
for _ in 1...numButtons+1 {
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = .red // just so we can see them... use .clear for production
spacers.append(v)
}
// addd spacers and buttons to stackView
for i in 0..<spacers.count {
stackView.addArrangedSubview(spacers[i])
// one fewer buttons than spacers, so don't go out-of-range
if i < buttons.count {
stackView.addArrangedSubview(buttons[i])
}
if i > 0 {
// constrain spacer widths to first spacer's width (this will make them all equal)
spacers[i].widthAnchor.constraint(equalTo: spacers[0].widthAnchor, multiplier: 1.0).isActive = true
// if you want the buttons to be equal widths, uncomment this block
/*
if i < buttons.count {
buttons[i].widthAnchor.constraint(equalTo: buttons[0].widthAnchor, multiplier: 1.0).isActive = true
}
*/
}
}
}
}
3 个按钮的结果:
并且有 4 个按钮:
还有几个等宽按钮:
我有一个带有 3 个按钮的水平堆栈视图:音乐应用程序的后退、播放、前进。 这是我当前的代码:
self.controlStackView.axis = .horizontal
self.controlStackView.distribution = .equalSpacing
self.controlStackView.alignment = .center
self.controlStackView.spacing = 10.0
self.controlStackView.translatesAutoresizingMaskIntoConstraints = false
self.contentView.addSubview(self.controlStackView)
self.controlStackView.topAnchor.constraint(equalTo: self.artworkImageView.bottomAnchor, constant: 10.0).isActive = true
self.controlStackView.centerXAnchor.constraint(equalTo: self.contentView.centerXAnchor).isActive = true
这是什么,它按如下方式分布按钮(由于对齐从中心开始):
[backward] - 10 spacing - [play] - 10 spacing - [forward]
我可以增加间距,但它仍然是固定的。 所以我设置了前导和尾随锚点来定义堆栈视图的最大宽度:
self.controlStackView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
self.controlStackView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
这对布局有何影响:
[left edge backward] - lots of spaaaaaaace - [centered play] - lots of spaaaaaaace - [right edge forward]
它分布在整个宽度上(并且中心向左和向右之间有一个.equalSpacing)。但这也无济于事。本质上,我的目标是拥有真正相等的间距,包括边缘。
假设我的可用宽度为 100,我的 3 个按钮分别为 10、20、10 - 这意味着还剩下 60 个 space 是空的。
我希望这样分发:
space - [backward] - space - [play] - space [forward] - space
所以我的按钮之间有 4 spaces,每个 space 是 15,所以我们填充剩余的 60 个 space。 我当然可以对堆栈视图实施填充以获得外部 space,但这将是相当静态的并且分布不均。
有谁知道我是否可以通过这种方式将边缘包含在 space 分布中?
谢谢
这真的很简单,使用 "spacer" 视图。
比按钮的数量多一个垫片,所以你有:
spacer - button - spacer - button - spacer
然后,将间隔物的宽度限制为 2 到 n 等于第一个间隔物的宽度。 stackView 将处理其余部分!
这里是一个例子(只需要一个viewController在storyboard中,其余的通过代码完成):
class DistributeViewController: UIViewController {
let stackView: UIStackView = {
let v = UIStackView()
v.translatesAutoresizingMaskIntoConstraints = false
v.axis = .horizontal
v.alignment = .fill
v.distribution = .fill
v.spacing = 0
return v
}()
var buttonTitles = [
"Backward",
"Play",
"Forward",
// "Next",
]
var numButtons = 0
override func viewDidLoad() {
super.viewDidLoad()
// stackView will hold the buttons and spacers
view.addSubview(stackView)
// constrain it to Top + 20, Leading and Trailing == 0, height will be controlled by button height
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20.0),
stackView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 0.0),
stackView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: 0.0),
])
// arrays to hold our buttons and spacers
var buttons: [UIView] = [UIView]()
var spacers: [UIView] = [UIView]()
numButtons = buttonTitles.count
// create the buttons and append them to our buttons array
for i in 0..<numButtons {
let b = UIButton()
b.translatesAutoresizingMaskIntoConstraints = false
b.backgroundColor = .blue
b.setTitle(buttonTitles[i], for: .normal)
buttons.append(b)
}
// create the spacer views and append them to our spacers array
// we need 1 more spacer than buttons
for _ in 1...numButtons+1 {
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = .red // just so we can see them... use .clear for production
spacers.append(v)
}
// addd spacers and buttons to stackView
for i in 0..<spacers.count {
stackView.addArrangedSubview(spacers[i])
// one fewer buttons than spacers, so don't go out-of-range
if i < buttons.count {
stackView.addArrangedSubview(buttons[i])
}
if i > 0 {
// constrain spacer widths to first spacer's width (this will make them all equal)
spacers[i].widthAnchor.constraint(equalTo: spacers[0].widthAnchor, multiplier: 1.0).isActive = true
// if you want the buttons to be equal widths, uncomment this block
/*
if i < buttons.count {
buttons[i].widthAnchor.constraint(equalTo: buttons[0].widthAnchor, multiplier: 1.0).isActive = true
}
*/
}
}
}
}
3 个按钮的结果:
并且有 4 个按钮:
还有几个等宽按钮: