Frakcool
Frakcool

Reputation: 11153

SwiftUI VStack align right single element

I'm new at SwiftUI, I'm trying this time to align right a single element (an image) to the right and then the rest of the content should be center aligned.

Just like what happens when you use Spacer() on an HStack but to the other side.

I read about .alignmentGuide and it was a little bit confusing but I tried using it this way:

struct ContentView: View {
    var body: some View {
        VStack {
            HStack {
                Text("Hello!").alignmentGuide(.trailing) {
                    v in v[HorizontalAlignment.trailing]
                }
            }
            Text("Hello, World!")
            Spacer()
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

But this makes no change at all, both Text are center aligned.

I tried moving the .alignmentGuide code after the } of the HStack with the same result.

This is what I'm trying to do, before with storyboards I'd use some constraints to do this, like setting the right constraint to 8 or something, but I'm a bit lost when it comes to doing it the SwiftUI way.

enter image description here

Upvotes: 17

Views: 14670

Answers (2)

Rémi B.
Rémi B.

Reputation: 2907

To answer to @cheesus, I would say @vacawama's answer is not the recommended way of doing it.

Here is how I would do it

VStack {
  Text("Hello!")
    .frame(maxWidth: .infinity, alignment: .trailing)
    .padding(.trailing, 8)
  Text("Hello, World!")
}
.frame(maxHeight: .infinity, alignment: .top)

To elaborate a bit more

The main problem with using (H|V)Stacks and Spacers is that you get a fixed spacing between your content and the Spacer, and in some cases it might cause issues.

An example

  • Consider we want a HStack, some spacing between elements and the last text aligned to the left:

    HStack(spacing: 25) {
      Color.red
        .frame(width: 50, height: 20)
      Color.green
        .frame(width: 50, height: 20)
      Text("The text")
        .background(Color.blue)
      Spacer()
    }
    .frame(width: 250)
    .border(Color.yellow)
    .padding(8)
    

    It gives: Example 1

  • If the text becomes longer, you see the HStack spacing between the spacer:

    - Text("The text")
    + Text("Some long text")
    

    Example 2

  • Now I just replaced the Spacer with a Color so you can see it in action:

    - Text("Some long text")
    -   .background(Color.blue)
    - Spacer()
    + Text("Some long text")
    +   .background(Color.blue)
    +   .layoutPriority(1)
    + Color.indigo
    +   .frame(height: 20)
    +   .frame(maxWidth: .infinity)
    

    Example 3

  • This is fixed if you use .frame(alignment:):

    HStack(spacing: 25) {
      Color.red
        .frame(width: 50, height: 20)
      Color.green
        .frame(width: 50, height: 20)
      Text("Some long text")
        .frame(maxWidth: .infinity, alignment: .leading)
        .background(Color.blue)
    }
    .frame(width: 250)
    .border(Color.yellow)
    .padding(8)
    

    Example 4

Upvotes: 18

vacawama
vacawama

Reputation: 154593

Here's one way to do it:

struct ContentView: View {
    var body: some View {
        VStack {
            HStack {
                Spacer()
                Text("Hello!")
                    .padding(.trailing, 8)
            }
            Text("Hello, World!")
            Spacer()
        }
    }
}

Use an HStack with a Spacer() to push Text("Hello!") to the right. Add .padding(.trailing, 8) to keep it 8 points off the right edge.

Upvotes: 23

Related Questions