Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 668
Frakcool Avatar asked Dec 22 '22 17:12

Frakcool


2 Answers

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.

like image 52
vacawama Avatar answered Dec 28 '22 15:12

vacawama


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

like image 41
Rémi B. Avatar answered Dec 28 '22 16:12

Rémi B.