Here I have a horizontal stack view with three subviews, however, it looks to be a bit off-centered as shown below.
I tried to:
- Constrain the stack view's centerXAnchor to be equal to the superview's centerXAnchor
- Set the stack view's alignment to center
How can I correctly align my stack view to the center of the superview?
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(macroStackView)
macroStackView.translatesAutoresizingMaskIntoConstraints = false
constrainView()
}
lazy var carbView: UIView = {
var view = UIView()
var iv = UIImageView(image: Image.planViewBg)
iv.frame = CGRect(x: 0, y: 0, width: 105, height: 118)
iv.contentMode = .scaleAspectFit
var label1 = UILabel()
label1.text = "31%"
label1.textAlignment = .center
var label2 = UILabel()
label2.text = "30g"
label2.textAlignment = .center
var label3 = UILabel()
label3.text = "Carbs"
label3.textAlignment = .center
var labelStack = UIStackView(arrangedSubviews: [label1, label2, label3])
labelStack.axis = .vertical
labelStack.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(iv)
iv.addSubview(labelStack)
NSLayoutConstraint.activate([
labelStack.centerXAnchor.constraint(equalTo: iv.centerXAnchor),
labelStack.centerYAnchor.constraint(equalTo: iv.centerYAnchor),
])
return view
}()
lazy var proteinView: UIView = {
var view = UIView()
var iv = UIImageView(image: Image.planViewBg)
iv.frame = CGRect(x: 0, y: 0, width: 105, height: 118)
iv.contentMode = .scaleAspectFit
var label1 = UILabel()
label1.text = "23%"
label1.textAlignment = .center
var label2 = UILabel()
label2.text = "23g"
label2.textAlignment = .center
var label3 = UILabel()
label3.text = "Protein"
label3.textAlignment = .center
var labelStack = UIStackView(arrangedSubviews: [label1, label2, label3])
labelStack.axis = .vertical
labelStack.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(iv)
iv.addSubview(labelStack)
NSLayoutConstraint.activate([
labelStack.centerXAnchor.constraint(equalTo: iv.centerXAnchor),
labelStack.centerYAnchor.constraint(equalTo: iv.centerYAnchor),
])
return view
}()
lazy var fatView: UIView = {
var view = UIView()
var iv = UIImageView(image: Image.planViewBg)
iv.frame = CGRect(x: 0, y: 0, width: 105, height: 118)
iv.contentMode = .scaleAspectFit
var label1 = UILabel()
label1.text = "46%"
label1.textAlignment = .center
var label2 = UILabel()
label2.text = "20g"
label2.textAlignment = .center
var label3 = UILabel()
label3.text = "Fat"
label3.textAlignment = .center
var labelStack = UIStackView(arrangedSubviews: [label1, label2, label3])
labelStack.axis = .vertical
labelStack.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(iv)
iv.addSubview(labelStack)
NSLayoutConstraint.activate([
labelStack.centerXAnchor.constraint(equalTo: iv.centerXAnchor),
labelStack.centerYAnchor.constraint(equalTo: iv.centerYAnchor),
])
return view
}()
lazy var macroStackView: UIStackView = {
var stack = UIStackView(arrangedSubviews: [carbView, proteinView, fatView])
stack.axis = .horizontal
stack.distribution = .fillEqually
stack.alignment = .center
return stack
}()
func constrainView() {
NSLayoutConstraint.activate([
macroStackView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
macroStackView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 30),
macroStackView.widthAnchor.constraint(equalTo: view.widthAnchor,
multiplier: 0.9)
])
}
}
CodePudding user response:
Tthe iv
s do not have its translatesAutoresizingMaskIntoConstraints
set to false. This makes its position fixed at (0, 0) within the view
s. The view
s are properly stretched by the stack view however, which is why a frame of (0, 0, 105, 118) leaves a lot of blank space on the right.
The alignment of a stack view describes how things are distributed perpendicular to the axis. In this case, the axis is horizontal, so alignment
is about how things align along the height of the stack view, not the width as you may have assumed. It seems like you want .fill
here - the "boxes" should fill the height of the stack view.
In any case, a simple solution is to position the iv
s correctly within the view
s by adding constraints.
You should first set
iv.translatesAutoresizingMaskIntoConstraints = false
as you are about to add constraints. Then add these constraints:
iv.widthAnchor.constraint(equalToConstant: 105),
iv.heightAnchor.constraint(equalToConstant: 118),
iv.centerXAnchor.constraint(equalTo: view.centerXAnchor),
iv.centerYAnchor.constraint(equalTo: view.centerYAnchor),
I also don't see anything that determines the height of macroStackView
. You should add a height constraint to macroStackView
.
macroStackView.heightAnchor.constraint(equalToConstant: 118)
Alternatively, you could un-embed iv
from the view
, and just return iv
directly.
lazy var carbView: UIView = {
var iv = UIImageView(image: Image.planViewBg)
iv.translatesAutoresizingMaskIntoConstraints = false
iv.contentMode = .scaleAspectFit
var label1 = ...
var label2 = ...
var label3 = ...
var labelStack = UIStackView(arrangedSubviews: [label1, label2, label3])
...
iv.addSubview(labelStack)
...
return iv
}()
In this case, you would need to set the spacing
of the stack view to achieve the spacing that you want.