SwiftUI:将视图与 VStack 中另一个视图的前缘和后缘对齐

Posted

技术标签:

【中文标题】SwiftUI:将视图与 VStack 中另一个视图的前缘和后缘对齐【英文标题】:SwiftUI: Aligning views to the leading & trailing edges of another view in a VStack 【发布时间】:2019-12-27 07:30:18 【问题描述】:

如何在 SwiftUI VStack 中将内容与另一个视图的前缘和后缘对齐?

我目前有以下 SwiftUI 代码:

struct MyBlock: View 
    var body: some View 
        Rectangle().foregroundColor(.gray).frame(width: 80, height: 80)
    


struct MyGridView: View 
    var body: some View 
        HStack(spacing: 16) 
            MyBlock()
            MyBlock()
            MyBlock()
                               
    


struct PinPad: View 
    var body: some View 
        VStack 
            MyGridView()
            HStack 
                Button(action: , label:  Text("Left Align") )
                Spacer()
                Button(action: , label:  Text("Right Align") )
            
        
    

结果呈现如下:

但我真正想要的是"Left Align" ButtonMyGridView 的左/前缘对齐,"Right Align" ButtonMyGridView 的右/后缘对齐.

例如,像这样:

我显然在这里遗漏了一些非常基本的东西,因为在 UIKit 中使用自动布局是微不足道的。

【问题讨论】:

【参考方案1】:

解决布局问题需要做的第一件事是在视图上添加边框。这将使您看到视图的真实(和不可见)界限。问题会更清楚:

在您的情况下,可以通过将其全部包装在 HStack 中并添加一些垫片来轻松修复:

struct PinPad: View 
    var body: some View 
        HStack 
            Spacer()
            VStack 
                MyGridView().border(Color.blue, width: 3)
                HStack 
                    Button(action: , label:  Text("Left Align") ).border(Color.red, width: 3)
                    Spacer()
                    Button(action: , label:  Text("Right Align") ).border(Color.red, width: 3)
                
            .border(Color.green, width: 3)
            Spacer()
        
    

【讨论】:

这当然有效。除非有人能想出一个更优雅的解决方案,否则我现在就试一试。【参考方案2】:

GeometryReader 是一个视图,可让您访问父母的大小和位置

定义了一个名为 GeometryGetter 的视图,

struct GeometryGetter: View 

    @Binding var rect: CGRect

    var body: some View 
        return GeometryReader  geometry in
            self.makeView(geometry: geometry)
        
    

    func makeView(geometry: GeometryProxy) -> some View 
        DispatchQueue.main.async 
            self.rect = geometry.frame(in: .global)
        

        return Rectangle().fill(Color.clear)
    

然后将代码更改如下,

struct PinPad: View 

    @State private var rect: CGRect = CGRect()

    var body: some View 
        HStack 
            VStack 
                MyGridView().background(GeometryGetter(rect: $rect))
                HStack 
                    Button(action: , label:  Text("Left Align") )
                    Spacer()
                    Button(action: , label:  Text("Right Align") )
                .frame(width: rect.width)
            
        
    

【讨论】:

【参考方案3】:

您可以在 VStack 之后添加 .fixedSize()。

【讨论】:

【参考方案4】:

.fixedSize() 添加到您的 VStack 可以解决问题。

struct PinPad: View 
    var body: some View 
        VStack 
            MyGridView()
            HStack 
                Button(action: , label:  Text("Left Align") )
                Spacer()
                Button(action: , label:  Text("Right Align") )
            
        
        .fixedSize()
    

简要说明:

关于自动布局的基本内容,在 swiftui 中取决于框架 我们使用的不同堆栈堆栈。在这个查询中,第一个 VStack 是 父视图,它围绕它的 childView 作为它的框架 它是明确提供的。但是,由于按钮的 HStack 没有提供任何明确的宽度,但由于Spacer(); (这明确地使按钮拖动到它们的边缘),HStack 的 框架具有可用屏幕大小的宽度,这使得父级 VStack 视图也随之放大。因此,我们需要 还要注意子视图框架以及父视图 查看。

额外信息:-alignment: 添加到堆栈本身只会对齐该视图中的内容,而添加.frame(alignment:) 修饰符将对齐视图本身。

【讨论】:

以上是关于SwiftUI:将视图与 VStack 中另一个视图的前缘和后缘对齐的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI,删除VStack中视图之间的空间?

带有灵活 Spacer 的 SwiftUI VStack

SwiftUI VStack 和 List 中其他视图压缩的视图

如何将 UIActivityViewController 与 SwiftUI 的 ScrollView 集成?

SwiftUI VStack 间距:无法正常工作

SwiftUI之HStack和VStack的切换