SwiftUI:如何在VStack中将视图对齐到另一个视图的前沿和后沿

14

在 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") })
            }
        }
    }
}
结果如下所示:

结果呈现如下:

Spacer consumes all the available space

但我真正想要的是将“左对齐”按钮与 MyGridView 的左边缘/前沿对齐,将“右对齐”按钮与 MyGridView 的右边缘/后沿对齐。

例如,就像这样:

Aligned Buttons

显然,我在这里漏掉了一些非常基本的东西,因为在UIKit中使用自动布局要容易得多。

4个回答

24

要解决布局问题,第一步是在视图上添加边框。这样可以让您看到视图的实际(和不可见)边界。问题将变得更加清晰:

enter image description here

在您的情况下,可以通过将所有内容包装在HStack中并添加一些间距来轻松解决:

enter image description here

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

这肯定可以。除非有人能想出更优雅的解决方案,否则我现在就试一下。 - orj

3

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

1
.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中取决于我们使用的不同Stack的框架。在这个查询中,第一个VStack是父视图,它包裹了它的子视图以获得显式提供的框架。但是,由于按钮的HStack没有提供任何明确的宽度,但由于Spacer()(它明确地使按钮拖到它们的边缘),HStack的框架具有屏幕可用大小的宽度,这也使得父VStack视图随之扩大。因此,我们需要注意子视图的框架以及父视图。

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


1
你可以在 VStack 后面添加 .fixedSize()。

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