llllbbbbllll
llllbbbbllll

Reputation: 693

How to align elements in left, center, and right within HStack?

I'm creating an iOS minesweeper game and want to have a bar at the top with three pieces of information:

However, the elements are not evenly aligned as you can see in the picture at the bottom- I'm guessing the spacers are automatically the same size. So, because the text on the left side of the screen is wider than that on the right, the middle text is offset to the right.

How can I align these items so the center time/image is perfectly in the middle with the other objects on the left/right?

My code looks like:

struct GameView: View {
    @EnvironmentObject var game: Game
    @State var labelHeight = CGFloat.zero
    
    var body: some View {
        VStack(alignment: .center, spacing: 10) {
            Text("MINESWEEPER")
                .font(.system(size: 25, weight: .bold, design: .monospaced))
                .kerning(3)
                .foregroundColor(.red)
            
            HStack(alignment: .center, spacing: 5) {
                Image(systemName: "rosette")
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .foregroundColor(.black)
                Text(game.highScoreString)
                    .font(.system(size: 15, weight: .bold, design: .monospaced))
                    .foregroundColor(.black)

                Spacer()
                
                Image(systemName: "timer")
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .foregroundColor(.black)
                Text(game.timerString)
                    .font(.system(size: 15, weight: .bold, design: .monospaced))
                    .foregroundColor(.black)
                
                Spacer()
                
                Image("top_bomb")
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                Text(String(game.bombsRemaining))
                    .font(.system(size: 15, weight: .bold, design: .monospaced))
                    .foregroundColor(.black)
                    .overlay(GeometryReader(content: { geometry in
                        Color.clear
                            .onAppear(perform: {self.labelHeight = geometry.frame(in: .local).size.height})
                    }))
            }
            .frame(width: UIScreen.main.bounds.width * 0.9, height: labelHeight, alignment: .center)

            BoardView()
        }
    }
}

Game View Image

Upvotes: 59

Views: 63656

Answers (4)

Maksym Ovsianikov
Maksym Ovsianikov

Reputation: 509

In case if you need to achieve this within the NavigationView List toolbar for the ToolbarItems alignment you can use:

NavigationView {

    List { 
        // Your list elements go here
    }
    .toolbar {

        // To place element (ToolbarItem) on the left side
        ToolbarItem(placement: .navigationBarLeading) {
            Text("Left")
        }

        // To place element (ToolbarItem) in the middle (center)
        ToolbarItem(placement: .principal) {
            Text("Center")
        } 

        // To place element (ToolbarItem) on the right side 
        ToolbarItem(placement: .navigationBarTrailing) {
            Text("Right")
        }
    }
} 

Upvotes: 0

Alex F
Alex F

Reputation: 79

    ZStack {
        HStack{
            Text("Left")
            Spacer()
            Text("Right")
        }
        Text("Center")
    }

Upvotes: 6

Rukshan
Rukshan

Reputation: 8066

This can be achieved using a ZStack , HStack and Spacers.

     ZStack{
            
            HStack{
                Text("Left")
                Spacer()
            }
            
            HStack{
                Text("Center")
            }

            HStack{
                Spacer()
                Text("Right")
            }
            
        }

Even if you remove left ( or right ) HStack, it won't affect the other components or the layout.

You can make it look bit nicer by adding paddings like this,

ZStack{
            
            HStack{
                Text("Left").padding([.leading])
                Spacer()
            }
            
            HStack{
                Text("Center")
            }

            HStack{
                Spacer()
                Text("Right").padding([.trailing])
            }
            
        }

Upvotes: 18

Asperi
Asperi

Reputation: 258541

Instead of aligning by spacers, move each part into separate view, say LeftHeader, CenterHeader, and RightHeader and use frame alignment, which gives exact separation by equal sizes, like

HStack {
  LeftHeader()
    .frame(maxWidth: .infinity, alignment: .leading)
  CenterHeader()
    .frame(maxWidth: .infinity, alignment: .center)
  RightHeader()
    .frame(maxWidth: .infinity, alignment: .trailing)
}

Upvotes: 86

Related Questions