0
votes

How do I align elements in two different HStacks contained within a VStack in SwiftUI?

Here's what I'm trying to do -

VStack {
   HStack {
     element A - Text
     element B - Image 
     element C - Image
   }
   HStack {
     element D - Text
     element E - Text
   }
}

How do I align 'Text element D' in the 2nd HStack based on the center axis of 'Text element A' in the 1st HStack?

If I use the .center alignment on the all enclosing VStack it aligns the HStacks but not the individual elements to each other

Thanks in advance!

EDIT 1: @E.coms Based on your input this is what I'm doing

enter code here
import SwiftUI
struct ContentView2: View {

    var body: some View {  

        VStack(alignment: .center) {

            Image(systemName: "photo")
                .padding(.bottom, 10)       

            VStack(alignment: .midNameAndDate) {  

                HStack{
                    Text("Name")
                        .padding(.trailing, 100)
                        .alignmentGuide(.midNameAndDate, computeValue: { v in v[HorizontalAlignment.center] })
                    Image(systemName: "phone")
                        .padding(.trailing, 20)
                    Image(systemName: "location")
                        .padding(.trailing, 40)
                }        

                HStack {

                    Text("Month day, year")
                        .padding(.trailing, 40)
                    Text("00:00 ZM")
                        .padding(.trailing, 40)
                }.alignmentGuide(.midNameAndDate) { v in v[.leading]}

            }
        }
    }
}    

struct ContentView2_Previews: PreviewProvider {
    static var previews: some View {
        ContentView2()
    }
}

extension HorizontalAlignment {
    private enum MidNameAndDate : AlignmentID {
        static func defaultValue(in d: ViewDimensions) -> CGFloat {
            return d[.leading]
        }
    }
    static let midNameAndDate = HorizontalAlignment(MidNameAndDate.self)
}

'''

This is what I end up with

enter image description here

This is what I need instead

enter image description here

Should I rather split each of them as a VStack within a HStack?

On the other hand I am able to align them by splitting them as individual vertical stack (i.e. Name & Date under one vertical stack and Phone, Location & Time under another vertical stack. With both vertical stacks under a horizontal stack). But this becomes increasingly complicated when I want to create a list of these elements.

I was able to find information on aligning UIelements in different horizontal stacks at the WWDC 2019 videos, but nothing on aligning UIelements in different vertical stacks, at least I hope I'm not overlooking something!

1

1 Answers

2
votes

I show you a sample like the following:

                         extension HorizontalAlignment {
                            private enum MyAlignment: AlignmentID {
                                static func defaultValue(in d: ViewDimensions) -> CGFloat {
                                    return d[.trailing]
                                }
                            }
                            static let myAlignment = HorizontalAlignment(MyAlignment.self)
                        }



                        VStack(alignment: .myAlignment) {
                           HStack {
                             (element A).alignmentGuide(.myAlignment) { v in  v[HorizontalAlignment.center]}
                             (element B)
                             (element C)
                           }
                           HStack {
                             (element D)
                             (element E)
                            }.alignmentGuide(.myAlignment) { v in v[.leading]}
                        }

In you latest example, it should be like the following:

struct ContentView2: View {

var body: some View {

    VStack(alignment: .midNameAndDate) {

        Image(systemName: "photo")
            .padding(.bottom, 10).alignmentGuide(.midNameAndDate) { v in v[HorizontalAlignment.center]}

        VStack(alignment: .midNameAndDate) {

            HStack{
                Text("Name")
                    .padding(.trailing, 100)
                      .alignmentGuide(.midNameAndDate, computeValue: { v in v[HorizontalAlignment.center] + 25 })
                Image(systemName: "phone")
                    .padding(.trailing, 20)
                Image(systemName: "location")
                    .padding(.trailing, 40)
            }

            HStack {

                Text("Month day, year").alignmentGuide(.midNameAndDate) { v in v[.trailing]}
                    .padding(.trailing, 40)
                Text("00:00 ZM")
                    .padding(.trailing, 40)
            }

        }
    }.frame(maxWidth: .infinity, alignment: .trailing)


}
}

You can image the customized horizontal alignment is a line on your view elements. They should be at the same position with same midNameAndDate. Because you are using arbitrary trailing padding, you have to use the constants in your adjustment.

As to the container, use frame alignment to position the whole view in any superView.