戴夫·亚伯拉罕斯(Dave Abrahams)在WWDC19中关于“自定义视图”的讨论中解释了SwiftUI布局的一些机制,但是他遗漏了一些内容,因此我难以正确调整视图大小。
视图是否可以告诉其容器它没有占用任何空间,但是会使用给定的所有空间?换句话说,容器应拥抱其子视图。
具体示例,我想要类似c:
如果在Text
中有一些VStack
,如a)所示,则VStack
将采用其宽度作为最宽子视图。
如果您按照b)的方式添加Rectangle
,它将尽可能扩展,直到VStack
填充其容器。
这表示Text
和Rectangle
在布局方面属于不同的类别,Text
具有固定的大小,而Rectangle
是贪婪的。 但是如果我自己制作View
,如何将其传达给我的容器?
我实际上想要达到的结果是c)。 VStack在确定其大小时应忽略Rectangle(或我的自定义视图),然后做到这一点,然后然后将其告知Rectangle或我的自定义视图可以容纳多少空间。 / p>
鉴于SwiftUI似乎是自下而上地布局,也许这是不可能的,但似乎应该有some
的方式来实现这一目标。
答案 0 :(得分:2)
没有修饰符(AFAIK)可以完成此操作,所以这是我的方法。如果您经常使用此功能,则值得创建自己的修饰符。
还要注意,这里我使用的是标准首选项,但锚首选项甚至更好。这里要解释一个繁重的话题。我正在写一篇有关它的文章,一旦完成,我会在这里发布一个链接。
同时,您可以使用下面的代码来完成所需的工作。
import SwiftUI
struct MyRectPreference: PreferenceKey {
typealias Value = [CGRect]
static var defaultValue: [CGRect] = []
static func reduce(value: inout [CGRect], nextValue: () -> [CGRect]) {
value.append(contentsOf: nextValue())
}
}
struct ContentView : View {
@State private var widestText: CGFloat = 0
var body: some View {
VStack {
Text("Hello").background(RectGetter())
Text("Wonderful World!").background(RectGetter())
Rectangle().fill(Color.blue).frame(width: widestText, height: 30)
}.onPreferenceChange(MyRectPreference.self, perform: { prefs in
for p in prefs {
self.widestText = max(self.widestText, p.size.width)
}
})
}
}
struct RectGetter: View {
var body: some View {
GeometryReader { geometry in
Rectangle()
.fill(Color.clear)
.preference(key: MyRectPreference.self, value: [geometry.frame(in: .global)])
}
}
}
答案 1 :(得分:0)
所以我实际上找到了一种方法。首先,我尝试以各种配置将Spacers放置在视图周围,以尝试将其组合在一起,但这没有用。然后我意识到我也许可以使用.background修饰符,并且确实起作用了。似乎首先要让拥有视图计算其大小,然后才将其作为其框架,这正是我想要的。
这只是一个例子,有些技巧可以使高度正确,但这只是一个很小的细节,在我的特殊用例中,它是不需要的。如果您足够聪明,可能不在这里。
var body: some View {
VStack(spacing: 10) {
Text("Short").background(Color.green)
Text("A longer text").background(Color.green)
Text("Dummy").opacity(0)
}
.background(backgroundView)
.background(Color.red)
.padding()
.background(Color.blue)
}
var backgroundView: some View {
VStack(spacing: 10) {
Spacer()
Spacer()
Rectangle().fill(Color.yellow)
}
}
蓝色视图和所有彩色背景当然只是为了使其更易于查看。 这段代码产生了这一点: