mdav132
mdav132

Reputation: 175

SwiftUI Align HStack with different size elements

I am looking to build an HStack that has 3 elements in it, one to the left, one in the middle and one to the right. The middle element should always be in the centre, but because the left and right elements are dynamic and so can be different lengths the middle element is getting pushed depending on the size of the side elements (see picture below). I am using spacers and padding, but need something that will auto adjust the size of the spacers. Does anyone know of a way to do this?

See code attached below:

VStack(alignment: .leading){
                    Text(item.itemName)
                        .padding(1)
                        .padding(.horizontal, 20)
                    
                    HStack{
                        //Representative item code
                        Text("123454")
                            .padding(.horizontal, 20)
                        Spacer()
                        
                        Text(item.itemQuantity)
                            //.position(x: 100)

                        Spacer()
                        Text(item.itemPrice)
                            .padding(.horizontal, 20)
                    }

                }

Image showing unaligned hstack items

Upvotes: 4

Views: 7334

Answers (3)

swiftPunk
swiftPunk

Reputation: 1

This is a way of doing this kind of works, with overlay:

enter image description here

struct ContentView: View {
    
    var body: some View {
        
        ForEach(0...10, id:\.self) { index in
            
            VStack {
                
                HStack {
                    
                    Text("Item " + String(describing: index))
                        .bold()
                        .padding(1)
                        .padding(.horizontal, 20)
                    
                    Spacer()
                }
                
                HStack {
                    
                    Text(String(describing: Int.random(in: Int.min...Int.max)/100))
                        .lineLimit(1)
                        .padding(.horizontal, 20)
                    
                    Spacer()
                    
                    Text(String(describing: Int.random(in: Int.min...Int.max)/100))
                        .lineLimit(1)
                        .padding(.horizontal, 20)
                }
                .overlay(Text("1"))
                .overlay(Color.red.opacity(0.5).frame(width: 1, height: 500, alignment: .center)) //Testing!
                
                Divider()
                
            }
            
        }
        
    }
}

Upvotes: 6

you could try using LazyVGrid instead of your HStack, something like this example:

struct ContentView: View {
    var columns: [GridItem] = [GridItem(.flexible()),GridItem(.flexible()),GridItem(.flexible())]
    let items = ["1111","2","33333"]
    
    var body: some View {
        VStack(alignment: .leading, spacing: 10) {
            Text("Puma Buckett Hat").padding(.horizontal, 20)
            List (items, id: \.self) { item in
                LazyVGrid(columns: columns, alignment: .leading, spacing: 6) {
                    Text(item)
                    Text(item+" more stuff")
                    Text(item)
                }
            }
        }
    }
}

Upvotes: 0

George
George

Reputation: 30481

You can set the left and right views to fill as much width as possible. This will make them both evenly split up the space, excluding the middle Text.

To achieve this, you set the maxWidth to .infinity, and then align them to the correct side.

You tried to use Spacer(), which made the Spacers have equal width. However, with this solution, you are making these views have equal width.

Example:

struct ContentView: View {
    var body: some View {
        VStack(alignment: .leading, spacing: 10) {
            Text("Puma Buckett Hat")

            HStack(spacing: 0) {
                Text("123454").frame(maxWidth: .infinity, alignment: .leading)

                Text("1")

                Text("35.99").frame(maxWidth: .infinity, alignment: .trailing)
            }
        }
        .padding()
    }
}

Result:

Result

Adding border to each element in HStack to show how the space is taken up:

Result 2

And what it looks like when you have multiple of these:

Result 3

Upvotes: 7

Related Questions