在 SwiftUI 中水平居中查看

Center View horizontally in SwiftUI

如何在 HStack 中水平居中 View (Image)?我希望按钮左对齐,图像在视图中水平居中。

目前我有这样的结构:

VStack {
        HStack {
            Button(action: {
                print("Tapped")
            }, label: {
                Image("left-arrow")
                    .resizable()
                    .frame(width: 30, height: 30, alignment: .leading)
            }).padding(.leading, 20)
            
            Spacer()
            
            Image("twitter-logo")
                .resizable()
                .frame(width: 30, height: 30, alignment: .center)
            
        }
        Spacer()
    }

这是给我的:

但是我想实现这个:

如何将按钮大小保存为 属性 并向图像添加负边距?并且注意图片后面多了一个spacer

struct ContentView: View {

    var buttonSize: Length = 30

    var body: some View {
        VStack {
            HStack {
                Button(action: {
                    print("Tapped")
                }, label: {
                    Image(systemName: "star")
                        .resizable()
                        .frame(width: buttonSize, height: buttonSize, alignment: .leading)
                })
                Spacer()
                Image(systemName: "star")
                    .resizable()
                    .frame(width: 30, height: 30, alignment: .center)
                    .padding(.leading, -buttonSize)
                Spacer()
            }
            Spacer()
        }
    }
}

结果:

您可以将两个 HStack 嵌入一个 ZStack 中,并根据水平间距放置相应的垫片。将所有内容嵌入 VStackSpacer() 以将所有内容推到顶部。

struct ContentView : View {
    var buttonSize: Length = 30
    var body: some View {
        VStack {
            ZStack {
                HStack {
                    Button(action: {
                        
                    }, label: {
                        Image(systemName: "star")
                            .resizable()
                            .frame(width: CGFloat(30), height: CGFloat(30), alignment: .leading)
                    }).padding(.leading, CGFloat(20))
                    
                    Spacer()
                }
                
                HStack {
                    Image(systemName: "star")
                        .resizable()
                        .frame(width: CGFloat(30), height: CGFloat(30), alignment: .center)
                }
            }
            Spacer()
        }
    }
}

注意:在第二个 HStack 中,图像应该自动居中对齐,但如果不是,您可以在图像前后放置一个 Spacer()

编辑:添加了 VStackSpacer() 以将所有内容移动到顶部,就像 OP 想要的那样。

编辑 2:删除了图像上的填充,因为它导致图像稍微偏离中心。因为它在它自己的 HStack 和 center-aligned 中,所以不需要填充。

编辑 3:感谢评论中的@Chris Prince,我决定制作一个简单的 NavigationBar-esque 自定义视图,您可以提供左、中、右参数来创建 OP 所需的效果(其中每组视图彼此独立对齐):

struct CustomNavBar<Left, Center, Right>: View where Left: View, Center: View, Right: View {
    let left: () -> Left
    let center: () -> Center
    let right: () -> Right
    init(@ViewBuilder left: @escaping () -> Left, @ViewBuilder center: @escaping () -> Center, @ViewBuilder right: @escaping () -> Right) {
        self.left = left
        self.center = center
        self.right = right
    }
    var body: some View {
        ZStack {
            HStack {
                left()
                Spacer()
            }
            center()
            HStack {
                Spacer()
                right()
            }
        }
    }
}

用法:

struct ContentView: View {
    let buttonSize: CGFloat = 30
    var body: some View {
        VStack {
            CustomNavBar(left: {
                Button(action: {
                    print("Tapped")
                }, label: {
                    Image(systemName: "star")
                        .resizable()
                        .frame(width: self.buttonSize, height: self.buttonSize, alignment: .leading)
                }).padding()
            }, center: {
                Image(systemName: "star")
                    .resizable()
                    .frame(width: 30, height: 30, alignment: .center)
            }, right: {
                HStack {
                    Text("Long text here")
                    Image(systemName: "star")
                        .resizable()
                        .frame(width: 30, height: 30, alignment: .center)
                        .padding(.trailing)
                }.foregroundColor(.red)
            })
            Spacer()
            Text("Normal Content")
            Spacer()
        }
    }
}

您使用位置居中视图 属性 试试这个代码

Group{ // container View
   Image("twitter-logo")
            .resizable()
            .frame(width: 30, height: 30, alignment: .center)
}.position(x: UIScreen.main.bounds.width/2)

对我来说最简单的方法:

ZStack(){
    HStack{
        Image("star").resizable().foregroundColor(.white).frame(width: 50, height: 50)
        Spacer()
    }
        Image("star").resizable().font(.title).foregroundColor(.white).frame(width: 50, height: 50)
}

我有一个替代解决方案。我使用隐藏图像作为占位符。

HStack {
    Image("left-arrow").padding()
    Spacer()
    Image("twitter-logo")
    Spacer()
    // placeholder to keep layout symmetric
    Image("left-arrow").padding().hidden()
}

当然,您可以根据需要将图像替换为按钮或其他视图。

让我提出一个不同的解决方案:

https://gist.github.com/buscarini/122516641cd0ee275dd367786ff2a736

可以这样使用:

HStack {
    Color.red
        .frame(width: 0, height: 50)
        .layoutPriority(1)
        
    GlobalHCenteringView {
        Text("Hello, world!")
            .lineLimit(1)
            .background(Color.green)
    }
    .background(Color.yellow)
    
    Color.red
        .frame(width: 180, height: 50)
        .layoutPriority(1)
    }
}

如果适合,这将使子视图在屏幕中居中,如果不适合,则保持原样。它目前正在使用 UIScreen,因此它仅适用于 iOS,但您可以轻松地将屏幕或父宽度传递给视图的构造函数,从 GeometryReader 或其他任何东西获取它。

让标题像导航栏一样居中的正确方法:

HStack {

    Spacer()
        .overlay {
            HStack {
                Image(systemName: "star")
                Spacer()
            }
        }

    Text("Title")
             
    Spacer()
        .overlay {
            HStack {
                Spacer()
                Image(systemName: "star")
            }
        }
}