'How to make a view between Spacers always at the center in an HStack?
What I would like to achieve. regardless the width of text width at both side the button should always at the center of the HStack
.
HStack {
Text("Foooooooo")
Spacer(minLength: 5)
Button(action: { }) {
Text("Bar")
}
Spacer()
Text("Baz")
}
.font(.system(size: 16, weight: .heavy, design: .rounded))
.padding()
I also tried to use GeometryReader
and set frame size for each Text
and Button
in the view however there are two problems,
- The view returned by
GeometryReader
would occupies the entire view the parent offers to it instead of the actual intrinsic content size, the space only enough forText
,Spacer
andButton
- String inside the first
Text
could not be left align so does the string inside the lastText
couldn't be right aligned
Solution 1:[1]
Here is possible approach for your case. Demo prepared & tested with Xcode 12 / iOS 14
HStack {
Spacer()
.overlay(Text("Foooooooo"), alignment: .leading)
Button(action: { }) {
Text("Bar")
}
Spacer()
.overlay(Text("Baz"), alignment: .trailing)
}
.font(.system(size: 16, weight: .heavy, design: .rounded))
.padding()
Solution 2:[2]
You want to layout three flexible-but-same-sized elements, but you have three fixed-but-differently-sized elements. To fix that, put each element in its own flexible stack (HStack w/ spacer) so that each get 1/3 of the space. Within each stack, use Spacers to align.
HStack {
// Left stack
HStack {
Text("Foooooooo")
Spacer()
}
// Center stack. The surrounding Spacers aren't really required in this
// specific case, but added for consistency and to show how to center.
HStack {
Spacer()
Button(action: { }) {
Text("Bar")
}
Spacer()
}
// Right stack
HStack {
Spacer()
Text("Baz")
}
}
.font(.system(size: 16, weight: .heavy, design: .rounded))
.padding()
Solution 3:[3]
Here is another way to do it which is pretty concise and uses a ZStack
to combine the centered button with an HStack
with a single Spacer
to push the labels to the edges:
ZStack {
HStack {
Text("Foooooooo")
Spacer()
Text("Baz")
}
Button(action: { }) {
Text("Bar")
}
}
.font(.system(size: 16, weight: .heavy, design: .rounded))
.padding()
Note: This solution works if you know your labels won't encroach on your button. @Asperi's solution causes extra long labels to be truncated with ...
. @RobNapier's solution causes extra long labels to wrap at 1/3 of the width.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Rob Napier |
Solution 3 |