'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
GeometryReaderwould occupies the entire view the parent offers to it instead of the actual intrinsic content size, the space only enough forText,SpacerandButton - String inside the first
Textcould not be left align so does the string inside the lastTextcouldn'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 |



