如何使用 GeometryReader 实现 table 的布局?

How to use GeometryReader to achieve a table like layout?

我正在尝试实现这样的布局:

对于这个简单的例子,基础是这样的:

HStack {
  VStack {
    Text("Foo")
    Text("W")
    Text("X")
  }
  VStack {
    Text("Bar")
    Text("Y")
    Text("Z")
  }
}

现在 relativeSize(...) 已弃用,我看到的唯一剩余选项是 GeometryReader,但它的问题是一旦它本身嵌套在另一个堆栈中,它将尝试填充所有可用的space,换句话说,它无法确定它所包含的堆栈的大小,如果它不存在于其中,我最终会得到一个过大的堆栈。

我想知道我是否遗漏了什么,或者这是否就是堆栈的工作方式,或者可能是一个测试版错误?

感谢您的帮助

编辑: 我这样做了:

VStack {
GeometryReader { /* @kontiki code */ }
Text("Other")
Spacer().layoutPriority(1)
}

但不幸的是,这是我得到的结果,你认为这是 SwiftUI 的错误吗?

第二次尝试

我认为这正是您所需要的。它使用首选项。如果您需要了解有关如何使用 SwiftUI 首选项的更多信息,请查看我写的 post。它们在那里得到了充分的解释,但是post这里的主题太长了。

import SwiftUI

struct MyPref: PreferenceKey {
    typealias Value = CGFloat

    static var defaultValue: CGFloat = 0

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

struct SetWidthPreference: View {
    var body: some View {
        GeometryReader { proxy in
            Rectangle().fill(Color.clear).preference(key: MyPref.self, value: proxy.size.width)
        }
    }
}


struct ContentView : View {
    @State private var width: CGFloat = 0
    var body: some View {

        VStack {
            ScrollView {
                HStack(spacing: 0) {
                    VStack {
                        Text("Foo")
                        Text("Bar")
                    }.frame(width: width * 0.7, alignment: .leading).fixedSize().border(Color.red)

                    VStack {
                        Text("W")
                        Text("Y")
                    }.frame(width: width * 0.15).fixedSize().border(Color.red)

                    VStack {
                        Text("X")
                        Text("Z")
                    }.frame(width: width * 0.15).fixedSize().border(Color.red)
                }

                Text("Text below table")

            }
            .border(Color.green, width: 3)

            HStack { Spacer() }.background(SetWidthPreference())
        }
        .onPreferenceChange(MyPref.self) { w in
            print("\(w)")
            DispatchQueue.main.async {
                self.width = w
            }
        }
    }
}

上一次尝试(我把它放在这里,所以评论有意义)

此示例将绘制 3 列,宽度分别为父级的 0.7、0.15 和 0.15。这是您可以微调的起点。请注意,边框在那里,以便您可以看到您在做什么,当然您可以删除它们。

如果 GeometryReader 扩展得太多,请准确解释您想要完成的任务,并提供有关 table(即 GeometryReader)周围环境的更多上下文。

struct ContentView : View {
    var body: some View {

        GeometryReader { proxy in
            HStack(spacing: 0) {
                VStack {
                    Text("Foo")
                    Text("Bar")
                }.frame(width: proxy.size.width * 0.7, alignment: .leading).fixedSize().border(Color.red)

                VStack {
                    Text("W")
                    Text("Y")
                }.frame(width: proxy.size.width * 0.15).fixedSize().border(Color.red)

                VStack {
                    Text("X")
                    Text("Z")
                }.frame(width: proxy.size.width * 0.15).fixedSize().border(Color.red)
            }
        }.padding(20)
    }
}