xcode 在SwiftUI中水平居中视图

rpppsulh  于 2022-11-30  发布在  Swift
关注(0)|答案(8)|浏览(467)

如何在HStack中水平居中ViewImage)?我希望按钮左对齐,图像水平居中视图。
目前我有这样的结构:

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

这给了我这个:

但我要实现这一点:

qyswt5oh

qyswt5oh1#

你可以在一个ZStack中嵌入两个HStack,并放置相应的水平间距的间隔。将所有这些都嵌入一个VStack和一个Spacer(),以使所有东西都推到顶部。

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中并且中心对齐,所以不需要填充。
编辑3:感谢评论中的@Chris Prince,我决定创建一个简单的NavigationBar风格的自定义视图,您可以提供left、center和right参数来创建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()
        }
    }
}

wribegjk

wribegjk2#

如何将按钮大小保存到属性中,并在图像中添加一个负填充?注意图像后面的附加间隔。

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

结果:

v2g6jxz6

v2g6jxz63#

对我来说最简单的方法:

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

vfhzx4xs4#

使用position属性将视图居中,请尝试以下代码

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

sd2nnvve5#

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

HStack {

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

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

ojsjcaue6#

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

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

当然,您可以根据自己的喜好,用按钮或其他视图替换图像。

xxhby3vn

xxhby3vn7#

这是目前为止最好的答案。
您可以将想要置中的检视放置在VStack中,然后将alignment设定为center。请确定您也设定了frame(maxWidth: .infinity),否则它会将您的检视置中在VStack中,但VStack可能不会占据整个屏幕长度,因此您可能无法取得想要的外观。
为了使它更简单,可以将它写为extends对象的函数

extension View {
    func centerInParentView() -> some View {
        VStack(alignment: .center) {
            self
        }
        .frame(maxWidth: .infinity)
    }
}

然后您可以将其称为视图修饰符,即

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

每次都对我有效

ax6ht2ek

ax6ht2ek8#

让我提出一个不同的解决方案:
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)
    }
}

这将使子视图在屏幕上居中(如果合适),如果不合适,则保持原样。它当前使用UISscreen,因此仅在iOS上工作,但您可以轻松地将屏幕或父视图的宽度传递给视图的构造函数,从GeometryReader或其他工具获取它。

相关问题