如何使用 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)
}
}
我正在尝试实现这样的布局:
对于这个简单的例子,基础是这样的:
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)
}
}