4

我对这个问题有类似的问题(还没有答案): SwiftUI HStack with GeometryReader and paddings

不同的是,我的目标是对齐 HStack 内的两个视图,其中左视图获得可用宽度的 1/3,右视图获得可用宽度的 2/3。

在 ChildView 内部使用GeometryReader会弄乱整个布局,因为它会填满高度。

这是我的示例代码:

struct ContentView: View {
    var body: some View {
        VStack {
            VStack(spacing: 5) {
                ChildView().background(Color.yellow.opacity(0.4))
                ChildView().background(Color.yellow.opacity(0.4))
                Spacer()
            }

            .padding()

            Spacer()

            Text("Some random Text")
        }
    }
}

struct ChildView: View {
    var body: some View {
        GeometryReader { geo in
            HStack {
                Text("Left")
                    .frame(width: geo.size.width * (1/3))
                Text("Right")
                    .frame(width: geo.size.width * (2/3))
                    .background(Color.red.opacity(0.4))
            }
            .frame(minWidth: 0, maxWidth: .infinity)
            .background(Color.green.opacity(0.4))
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

结果是:

在此处输入图像描述

现在,如果您将此视图嵌入到其他视图中,则布局完全混乱:

例如在一个ScrollView

在此处输入图像描述

那么如何才能达到预期的结果HStack-ChildView 填充它获得的空间并在它的两个孩子之间划分它(1/3、2/3)的预期结果呢?

编辑

如答案中所述,我也忘记添加HStack(spacing: 0). 忽略这一点是右子容器溢出的原因。

4

1 回答 1

1

您可以为视图大小创建自定义PreferenceKey是一个例子:

struct ViewSizeKey: PreferenceKey {
    static var defaultValue: CGSize = .zero

    static func reduce(value: inout CGSize, nextValue: () -> CGSize) {
        value = nextValue()
    }
}

然后,创建一个将计算其大小并将其分配给的视图ViewSizeKey

struct ViewGeometry: View {
    var body: some View {
        GeometryReader { geometry in
            Color.clear
                .preference(key: ViewSizeKey.self, value: geometry.size)
        }
    }
}

现在,您可以在您的ChildView(即使它包含在 a 中ScrollView)使用它们:

struct ChildView: View {
    @State var viewSize: CGSize = .zero
    
    var body: some View {
        HStack(spacing: 0) { // no spacing between HStack items
            Text("Left")
                .frame(width: viewSize.width * (1 / 3))
            Text("Right")
                .frame(width: viewSize.width * (2 / 3))
                .background(Color.red.opacity(0.4))
        }
        .frame(minWidth: 0, maxWidth: .infinity)
        .background(Color.green.opacity(0.4))
        .background(ViewGeometry()) // calculate the view size
        .onPreferenceChange(ViewSizeKey.self) {
            viewSize = $0 // assign the size to `viewSize`
        }
                    
    }
}
于 2021-03-17T22:58:32.043 回答