skip to Main Content

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

  • The high score (next to a trophy symbol) [LEFT]
  • The current time (next to a timer symbol) [CENTER]
  • The number of bombs left (next to a bomb symbol) [RIGHT]

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

3

Answers


  1. 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)
    }
    
    Login or Signup to reply.
  2. 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])
                }
                
            }
    
    Login or Signup to reply.
  3. I think you can create more one stack.

    My solution like:

    /** 
    * spacing is an example
    * minWidth calculated by fontSize 
    */
    HStack(alignment: .center, spacing: 20){ 
        HStack{ Image, Text }.frame(minWidth: 30)
        HStack{ Image, Text }.frame(minWidth: 30)
        HStack{ Image, Text }.frame(minWidth: 30)
    }
    

    Hope it useful for you.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search