I'm working on trying to recreate the first SwiftUI Tutorial in code without using SwiftUI. In the example, it mentions using a Spacer
"to direct the layout to use the full width of the device":
VStack {
Text("Turtle Rock")
HStack {
Text("Joshua Tree National Park")
Spacer()
Text("California")
}
}
For the VStack
, HStack
, and Text
views, I can easily use UIStackView
and UILabel
. But for the Spacer
, I can't seem to find any equivalent in the standard library (no UISpacer
or anything like that), which makes me think this is something custom to SwiftUI. In the tutorial, it describes how this Spacer
works:
A spacer expands to make its containing view use all of the space of its parent view, instead of having its size defined only by its contents.
So how can I recreate the functionality of this Spacer
view programmatically? Do I just add a constraint to the UIStackView to make it full width? Or is there a way to add a subview to the UIStackView that makes it behave like it does in SwiftUI?
I have worked solution using dummy UIView()
which has set big constant widthConstraint
using low priority - this ensures UIView will grow as much as possible but will not grow over superview
constraints since it has lower priority.
Example:
let titleLabel = UILabel()
titleLabel.text = "Joshua Tree National Park"
let spacer = UIView()
// maximum width constraint
let spacerWidthConstraint = spacer.widthAnchor.constraint(equalToConstant: .greatestFiniteMagnitude) // or some very high constant
spacerWidthConstraint.priority = .defaultLow // ensures it will not "overgrow"
spacerWidthConstraint.isActive = true
let descriptionLabel = UILabel()
descriptionLabel.text = "California"
UIStackView(arrangedSubviews: [titleLabel, spacer, descriptionLabel])
You can create an extension for UIView
to create a spacer in this way:
extension UIView {
static func spacer(size: CGFloat = 10, for layout: NSLayoutConstraint.Axis = .horizontal) -> UIView {
let spacer = UIView()
if layout == .horizontal {
spacer.widthAnchor.constraint(equalToConstant: size).isActive = true
} else {
spacer.heightAnchor.constraint(equalToConstant: size).isActive = true
}
return spacer
}
}
After that, you can add your spacer into stacks in this way:
// ... some code
let stack = UIStackView(arrangedSubviews: [UIView.spacer(), UILabel(), UIView.spacer(), UILabel(), UIView.spacer()])
stack.axis = .horizontal
stack.distribution = .equalSpacing
// For vertical stacks
let stack = UIStackView(arrangedSubviews: [UIView.spacer(for: .vertical), UILabel(), UIView.spacer(for: .vertical), UILabel(), UIView.spacer(for: .vertical)])
stack.axis = .vertical
stack.distribution = .equalSpacing
I think in this way, you can play with spacer size/layout and stack distribution/alignment to get the desired space.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With