SwiftUI 如何在 HStack 中对齐子视图

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

这将导致以下结果:

enter image description here

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

例如在ScrollView

enter image description here

那么如何实现所需的结果呢?即具有填充其所占空间并在两个子视图之间分割(1/3,2/3)的HStack-ChildView?

编辑

正如回答中所述,我也忘记添加HStack(spacing: 0)。 这是右侧子容器溢出的原因。


我在你的代码中看到你想要2个ChildView()和一个Text,我认为你想让它们垂直平分1/3?而那个ChildView()有1/3和2/3的水平间距。 - ios coder
ScrollView 中,您期望 ChildView 元素有多高?它们失去了计算内在大小的能力,因为没有高度来约束它们。 - jnpdx
SwiftPunk: 我想限制水平间距。@jnpdx 我希望子视图/文本视图的行为与以前相同,只需要它们所需的高度。 - Ali
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中使用它们(即使它被包装在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`
        }
                    
    }
}

谢谢你的回答。它实际上解决了问题。我希望有一种更简单的方法,但这仍然有效! - Ali

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