This is probably a simple question but I am struggling hard.
Lets assume I have the following View Layout in SwiftUI
I want the Date String 10.5.2020
to be right aligned in the parent VStack.
But its important that by doing that, the intrinsic size of the VStack is not broken.
I am telling that because the two most obvious solutions are doing that.
HStack
and put a Spacer
on the left.maxWidth: .infinity
and alignment: .trailing
I had a deeper look into alignment guides but couldn't fix it with that.
My best results so far I have with GeometryReader
, setting width of the Text Label hardly to the width of the surrounding VStack.
But unfortunately my target structure is much more complex and this approach leads to issues in that structure. Also GeometryReader
seems inappropriate to do alignment.
struct ContentView: View {
var body: some View {
ScrollView {
VStack(alignment: .leading) {
HStack {
VStack(alignment: .leading) {
Text("Alignment Test")
Text("This is a longer text left aligned")
Text("10.5.2020")
}
.padding(16)
.background(Color.blue)
Spacer(minLength: 50)
}
HStack {
VStack(alignment: .leading) {
Text("left")
Text("Date should rigzht align to here <-")
Text("10.5.2020")
}
.padding(16)
.background(Color.blue)
Spacer(minLength: 50)
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.border(.red)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.gray.opacity(0.5))
}
}
Previews:
The alignment can be achieved using a combination of .frame
and .fixedSize
modifiers.
.frame(maxWidth: .infinity, alignment: .trailing)
to the text(s) you want right-aligned. This causes the text to extend to the maximum width available, with the content aligned to the right.Normally, this would cause the container to extend to the full width available too. So to prevent this from happening:
.fixedWidth()
to the VStack
. This tells it to adopt the ideal width of its contents.So the way it works is that the VStack
is sized to the ideal width of its contents, then, within this constraint, the maxWidth: .infinity
on the text takes effect.
ScrollView {
VStack(alignment: .leading) {
HStack {
VStack(alignment: .leading) {
Text("Alignment Test")
Text("This is a longer text left aligned")
Text("10.5.2020")
.frame(maxWidth: .infinity, alignment: .trailing) // π added
}
.padding(16)
.fixedSize() // π added
.background(Color.blue)
Spacer(minLength: 50)
}
HStack {
VStack(alignment: .leading) {
Text("left")
Text("Date should right align to here ->")
Text("10.5.2020")
.frame(maxWidth: .infinity, alignment: .trailing) // π added
}
.padding(16)
.fixedSize() // π added
.background(Color.blue)
Spacer(minLength: 50)
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.border(.red)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.gray.opacity(0.5))
EDIT In a comment, you said the longer text might be so long that it will need to wrap. But applying .fixedSize()
will prevent wrapping.
As an alternative approach, you could consider using a 1-column Grid
instead:
VStack
with Grid
..gridCellAnchor(.trailing)
to the dates.ScrollView {
VStack(alignment: .leading) {
HStack {
Grid(alignment: .leading) { // π VStack replaced
Text("Alignment Test")
Text("This is a longer text left aligned")
Text("10.5.2020")
.gridCellAnchor(.trailing) // π added
}
.padding(16)
.background(Color.blue)
Spacer(minLength: 50)
}
HStack {
Grid(alignment: .leading) {
Text("left")
Text("The quick brown fox jumps over the lazy dog")
Text("10.5.2020")
.gridCellAnchor(.trailing)
}
.padding(16)
.background(Color.blue)
Spacer(minLength: 50)
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.border(.red)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.gray.opacity(0.5))