SwiftUI - 如何在HStack中对齐元素到左侧、居中和右侧?

40

我正在创建一个iOS扫雷游戏,想要在顶部放一个栏,包含以下三个信息:

  • 最高分(旁边是一个奖杯符号)[左侧]
  • 当前时间(旁边是一个计时器符号)[中间]
  • 剩余炸弹数量(旁边是一个炸弹符号)[右侧]

然而,这些元素的对齐并不平均,就像您可以在底部的图片中看到的那样-我猜测空格自动具有相同的大小。因此,由于屏幕左侧的文本比右侧的文本更宽,所以中间的文本偏移向右。

我如何对齐这些项目,使得中心的时间/图像与左/右侧的其他对象完全居中对齐?

我的代码如下:

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()
        }
    }
}

游戏视图图片


1
只需添加一个Spacer()。 - Luchi Parejo Alcazar
4个回答

58

不要使用间隔符来对齐,而是将每个部分移到单独的视图中,比如 LeftHeaderCenterHeaderRightHeader,并使用框架对齐方式,这可以通过等大小的框架来实现确切的分离,例如:

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

1
使用这种方法,我发现默认的HStack间距值可能会导致中心标题偏离中心,因此明确设置HStack(spacing: 0)可能会有所帮助。 - Aaron T
如果我想自定义中间视图的对齐方式怎么办?我认为这个解决方案与这个答案相比并没有太大帮助:https://dev59.com/7lEG5IYBdhLWcg3wMmXB#74927217 - Mostafa Al Belliehy
捣乱ZStack意味着可能会出现元素重叠的情况,而这个解决方案则不是如此。这三个元素具有相同的空间,如果需要的话可以在垂直方向上扩展。 - itMaxence

12
这可以通过使用ZStack、HStack和Spacers来实现。
     ZStack{
            
            HStack{
                Text("Left")
                Spacer()
            }
            
            HStack{
                Text("Center")
            }

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

即使您删除左侧(或右侧)HStack,也不会影响其他组件或布局。
您可以通过添加padding来使其看起来更好,如下所示:
ZStack{
            
            HStack{
                Text("Left").padding([.leading])
                Spacer()
            }
            
            HStack{
                Text("Center")
            }

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

1
我更喜欢这个解决方案并投了赞成票。然而,中间的Text视图不需要使用HStack。我还使用了alignmentGuide()修饰符来自定义中间视图的对齐方式。 - Mostafa Al Belliehy
1
在整个 ZStack 上进行填充。我喜欢这个解决方案,特别是当只有两个视图(左边或右边的一个缺失)时。 - coco

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

3
你应该添加解释。 - Super Kai - Kazuya Ito

1

我认为你可以创建更多的堆栈。

我的解决方案如下:

/** 
* 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)
}

希望对你有用。

.center在HStack中是垂直居中的,所以我认为它在这里并不相关。 - itMaxence
哦,抱歉,这段代码是我在另一个实际案例中的解决方案,如果你需要的话,可以删除它。 - Nak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接