The following layout is easy to achieve with old-school Autolayout, but I can't see how to do the same thing with SwiftUI. Here is an example of the view I want to render:

This shows 3 variants of the same view. The view has 3 text children. Left, center, and right, with the following properties:
The best I could do is this sample below, but it has the drawback that the center view takes priority over the side views and thus clips them.
How can I achieve this with SwiftUI layout?
import SwiftUI
struct MyExample: View {
let leftText:String
let mainText:String
let rightText:String
var body: some View {
HStack{
HStack {
Text(self.leftText)
.modifier(MyBigFont())
Spacer()
}
Text(self.mainText)
.modifier(MyBigFont())
.layoutPriority(1.0)
HStack {
Spacer()
Text(self.rightText)
.modifier(MyBigFont())
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
VStack {
MyExample(leftText:"ABC", mainText:"1234", rightText:"XYZ").padding()
MyExample(leftText:"", mainText:"1234", rightText:"XYZ").padding()
MyExample(leftText:"ABC", mainText:"1234567890", rightText:"XYZ").padding()
Spacer()
}
}
}
struct MyBigFont: ViewModifier {
func body(content: Content) -> some View {
content
.lineLimit(1)
.font(Font.system(size: 42).bold())
}
}
Output:

This can uncenter the middle section if the left or right are so wide they would need to truncate, but other than that, I believe adding fixedSize() to the side Texts is all you need. fixedSize() on a Text indicates that it's not allowed to truncate or wrap, which is exactly what you're looking for.
var body: some View {
HStack{
HStack {
Text(self.leftText)
.modifier(MyBigFont())
.fixedSize() // <====
Spacer()
}
Text(self.mainText)
.modifier(MyBigFont())
.padding(.horizontal)
.layoutPriority(1.0)
HStack {
Spacer()
Text(self.rightText)
.modifier(MyBigFont())
.fixedSize() // <====
}
}
}

Your question in the comment is really good, and a great excuse to explain how this works. Nothing here is tricky IMO, so it's good to understand it.
From the 'layoutPriority' docs: "A parent layout should offer children with the highest layout priority all the space offered to the parent minus the minimum space required for all its lower-priority children, and so on for each lower priority value." (emphasis mine) Doesn't that imply SwiftUI should give the side texts a minimum size to fit their content?
SwiftUI is giving the side texts a minimum size to fit their content. The minimum size for a Text with tail-truncation is the space required to draw one character and an ellipsis. The ideal (horizontal) size is the size required to draw all of the text on one line without wrapping.
So the outer HStack first asks the two inner HStacks for their minimum sizes. They in turn ask their Text for its minimum size (the first character plus an ellipsis), and the Spacer's minimum is zero.
The outer HStack then takes those two minimums and subtracts them from its total and offers that to the center Text.
When you add fixedSize, that tells the Text to report its minimum size as the size required to draw the whole string on one line, so now each inner HStack has that as its minimum, and the center Text gets offered less space.
In both cases, the center Text then tells the outer HStack how much space it's going to use, truncating if necessary (since it doesn't have fixedSize).
The outer HStack subtracts that space and then considers the other two children. They are equally flexible (since both include a Spacer), so it offers half the space to the left one. The left one takes exactly what it was offered (*), and so the other half is offered to the right one, which also takes all of it.
(*) In most cases that we're talking about here. In a narrow enough container, it's possible that the minimum size required will be greater than what is available. In that case, the child will take more than it's offered, and things will overflow their bounds.
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