StackView 中的堆栈视图基于最小的项目平均填充
StackViews in StackViews Fill All Equally Based On Smallest Item
我正在尝试填充一个未知但计算出的 stackView 数量,填充一个未知但计算出的 UIImageView 数量,同样,间距相等。
我有一个主垂直 stackView,其高度和宽度限制为 75。对齐方式:居中;分配:平均填充。
对于每个 subStackView:
newStack.axis = .horizontal
newStack.alignment = .center
newStack.distribution = .fillEqually
newStack.spacing = 1
newStack.sizeToFit()
mainStack.addArrangedSubview(newStack)
然后我有一个不同的循环,将正确数量的 imageView 添加到每个 subStackView 中:
let image = UIImageView()
image.contentMode = .scaleAspectFit
image.image = UIImage(systemName: R.Image.System.circle)
subStackView.addArrangedSubview(image)
下面是结果的屏幕截图。看起来所有 imageView 的大小都相同,但出于某种原因,它们看起来是等距的,而不是 1 的间距。
下面的3张图应该都是五边形,但是你可以看到,添加的项目越多,形状就越扭曲。
这有点棘手...
我们需要让“点行”(水平堆栈视图)居中,而不是拉伸主堆栈视图的宽度。
我们还需要实际计算点宽而不是使用 .fillEqually
,这样我们就不会得到双边点的大小。
例如:
- 主堆栈宽度为 75
- 1 磅间距
- 3 个水平点
可用宽度是堆栈视图宽度减去“空格”数 x 间距:
75 - 2 = 73
73 / 3 = 24.333333...
在 @2x
比例设备上,3 个视图的实际宽度为:
24.5 : 24 : 24.5
只有 3 个“点”不是很明显,但是当我们达到 1, 3, 5, 7, 9, 8, 7, 6, 5
模式时它会变得非常明显。
.fillEqually
在左边,计算出的整数点大小在右边:
下面是一些示例代码:
class DotsViewController: UIViewController {
let patterns: [[Int]] = [
[3, 3, 3],
[3],
[1, 2, 3],
[1, 3, 5, 4, 3],
[1, 3, 5, 7, 9, 8, 7, 6, 5],
]
let mainStack: UIStackView = {
let v = UIStackView()
v.translatesAutoresizingMaskIntoConstraints = false
v.axis = .vertical
v.alignment = .fill
v.distribution = .equalSpacing
return v
}()
// space between dots
let dotSpacing: CGFloat = 1
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(mainStack)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// constrain main stack view 20-pts from top / leading / bottom
mainStack.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
mainStack.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
mainStack.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -20.0),
// width: 75
mainStack.widthAnchor.constraint(equalToConstant: 75.0),
])
patterns.forEach { a in
// create a vertical stack view
// to hold the "rows" of horizontal stack views (containing the dots)
let vBlockStack = UIStackView()
vBlockStack.axis = .vertical
vBlockStack.alignment = .center
vBlockStack.distribution = .fill
vBlockStack.spacing = dotSpacing
// add it to the main stack view
mainStack.addArrangedSubview(vBlockStack)
// calculate dot size
// needs to be a whole number so we don't get
// half-point sizes
let maxDots:CGFloat = CGFloat(a.max()!)
let availableWidth:CGFloat = 75.0 - ((maxDots - 1) * dotSpacing)
let w:CGFloat = floor(availableWidth / maxDots)
a.forEach { numDots in
// create a horizontal stack view
let hDotStack = UIStackView()
hDotStack.axis = .horizontal
hDotStack.alignment = .fill
hDotStack.distribution = .fill
hDotStack.spacing = dotSpacing
// add it to the vertical block stack view
vBlockStack.addArrangedSubview(hDotStack)
for _ in 0..<numDots {
let v = UIImageView()
v.contentMode = .scaleAspectFit
v.image = UIImage(systemName: "circle.fill")
v.tintColor = .red
// add view to dot stack view
hDotStack.addArrangedSubview(v)
// set dots image view size constraints
v.widthAnchor.constraint(equalToConstant: w).isActive = true
v.heightAnchor.constraint(equalTo: v.widthAnchor).isActive = true
}
}
}
}
}
产生此输出:
我正在尝试填充一个未知但计算出的 stackView 数量,填充一个未知但计算出的 UIImageView 数量,同样,间距相等。
我有一个主垂直 stackView,其高度和宽度限制为 75。对齐方式:居中;分配:平均填充。
对于每个 subStackView:
newStack.axis = .horizontal
newStack.alignment = .center
newStack.distribution = .fillEqually
newStack.spacing = 1
newStack.sizeToFit()
mainStack.addArrangedSubview(newStack)
然后我有一个不同的循环,将正确数量的 imageView 添加到每个 subStackView 中:
let image = UIImageView()
image.contentMode = .scaleAspectFit
image.image = UIImage(systemName: R.Image.System.circle)
subStackView.addArrangedSubview(image)
下面是结果的屏幕截图。看起来所有 imageView 的大小都相同,但出于某种原因,它们看起来是等距的,而不是 1 的间距。
下面的3张图应该都是五边形,但是你可以看到,添加的项目越多,形状就越扭曲。
这有点棘手...
我们需要让“点行”(水平堆栈视图)居中,而不是拉伸主堆栈视图的宽度。
我们还需要实际计算点宽而不是使用 .fillEqually
,这样我们就不会得到双边点的大小。
例如:
- 主堆栈宽度为 75
- 1 磅间距
- 3 个水平点
可用宽度是堆栈视图宽度减去“空格”数 x 间距:
75 - 2 = 73
73 / 3 = 24.333333...
在 @2x
比例设备上,3 个视图的实际宽度为:
24.5 : 24 : 24.5
只有 3 个“点”不是很明显,但是当我们达到 1, 3, 5, 7, 9, 8, 7, 6, 5
模式时它会变得非常明显。
.fillEqually
在左边,计算出的整数点大小在右边:
下面是一些示例代码:
class DotsViewController: UIViewController {
let patterns: [[Int]] = [
[3, 3, 3],
[3],
[1, 2, 3],
[1, 3, 5, 4, 3],
[1, 3, 5, 7, 9, 8, 7, 6, 5],
]
let mainStack: UIStackView = {
let v = UIStackView()
v.translatesAutoresizingMaskIntoConstraints = false
v.axis = .vertical
v.alignment = .fill
v.distribution = .equalSpacing
return v
}()
// space between dots
let dotSpacing: CGFloat = 1
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(mainStack)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// constrain main stack view 20-pts from top / leading / bottom
mainStack.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
mainStack.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
mainStack.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -20.0),
// width: 75
mainStack.widthAnchor.constraint(equalToConstant: 75.0),
])
patterns.forEach { a in
// create a vertical stack view
// to hold the "rows" of horizontal stack views (containing the dots)
let vBlockStack = UIStackView()
vBlockStack.axis = .vertical
vBlockStack.alignment = .center
vBlockStack.distribution = .fill
vBlockStack.spacing = dotSpacing
// add it to the main stack view
mainStack.addArrangedSubview(vBlockStack)
// calculate dot size
// needs to be a whole number so we don't get
// half-point sizes
let maxDots:CGFloat = CGFloat(a.max()!)
let availableWidth:CGFloat = 75.0 - ((maxDots - 1) * dotSpacing)
let w:CGFloat = floor(availableWidth / maxDots)
a.forEach { numDots in
// create a horizontal stack view
let hDotStack = UIStackView()
hDotStack.axis = .horizontal
hDotStack.alignment = .fill
hDotStack.distribution = .fill
hDotStack.spacing = dotSpacing
// add it to the vertical block stack view
vBlockStack.addArrangedSubview(hDotStack)
for _ in 0..<numDots {
let v = UIImageView()
v.contentMode = .scaleAspectFit
v.image = UIImage(systemName: "circle.fill")
v.tintColor = .red
// add view to dot stack view
hDotStack.addArrangedSubview(v)
// set dots image view size constraints
v.widthAnchor.constraint(equalToConstant: w).isActive = true
v.heightAnchor.constraint(equalTo: v.widthAnchor).isActive = true
}
}
}
}
}
产生此输出: