Reputation: 3225
How can I have an UIStackView with the same space as padding and gap between views?
How can I achieve this layout:
When this one doesn't suit me:
Neither does this:
I just need the around views space to be the same as the between views space. Why is it so hard?
Important
I'm using my fork of TZStackView to support iOS 7. So no layoutMargins
for me :(
Upvotes: 7
Views: 3627
Reputation: 1687
I know this is an older question, but the way I solved it was to add two UIViews with zero size at the beginning and end of my stack, then use the .equalSpacing
distribution.
Note: this only guarantees equal around spacing along the main axis of the stack view (i.e. the left and right edges in my example)
let stack = UIStackView()
stack.axis = .horizontal
stack.alignment = .center
stack.distribution = .equalSpacing
// add content normally
// ...
// add extra views for spacing
stack.insertArrangedSubview(UIView(), at: 0)
stack.addArrangedSubview(UIView())
Upvotes: 10
Reputation: 3225
For those who keep getting here looking for a solution for this problem. I found that the best way (in my case) would be to use a parent UIView
as background and padding, like this:
In this case the UIStackView
is contrained to the edges of the UIView
with a padding and separate the subviews with spacing.
Upvotes: 2
Reputation: 27620
You can almost achieve what you want using a UIStackView. When you set some constraints yourself on the UIViews inside the UIStackView you can come up with this:
This is missing the left and right padding that you are looking for. The problem is that UIStackView
is adding its own constraints when you add views to it. In this case you can add top
and bottom
constraints to get the vertical padding, but when you try to add a trailing
constraint for the right padding, UIStackView
ignores or overrides that constraint. Interestingly adding a leading
constraint for the left padding works.
But setting constraints on UIStackView's
arranged subviews is not what you want to do anyway. The whole point of using a UIStackView
is to just give it some views and let UIStackView
handle the rest.
To achieve what you are trying to do is actually not too hard. Here is an example of a UIViewController
that contains a custom stack view that can handle padding on all sides (I used SnapKit for the constraints):
import UIKit
import SnapKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let padding: CGFloat = 30
let customStackView = UIView()
customStackView.backgroundColor = UIColor(white: 0, alpha: 0.1)
view.addSubview(customStackView)
customStackView.snp_makeConstraints { (make) -> Void in
make.top.left.equalTo(padding)
make.right.equalTo(-padding)
}
// define an array of subviews
let views = [UIView(), UIView(), UIView()]
// UIView does not have an intrinsic contentSize
// so you have to set some heights
// In a real implementation the height will be determined
// by the views' content, but for this example
// you have to set the height programmatically
views[0].snp_makeConstraints { (make) -> Void in
make.height.equalTo(150)
}
views[1].snp_makeConstraints { (make) -> Void in
make.height.equalTo(120)
}
views[2].snp_makeConstraints { (make) -> Void in
make.height.equalTo(130)
}
// Iterate through the views and set the constraints
var leftHandView: UIView? = nil
for view in views {
customStackView.addSubview(view)
view.backgroundColor = UIColor(white: 0, alpha: 0.15)
view.snp_makeConstraints(closure: { (make) -> Void in
make.top.equalTo(padding)
make.bottom.lessThanOrEqualTo(-padding)
if let leftHandView = leftHandView {
make.left.equalTo(leftHandView.snp_right).offset(padding)
make.width.equalTo(leftHandView)
} else {
make.left.equalTo(padding)
}
leftHandView = view
})
}
if let lastView = views.last {
lastView.snp_makeConstraints(closure: { (make) -> Void in
make.right.equalTo(-padding)
})
}
}
}
This produces the following results:
Upvotes: 7