Dave在他的关于自定义视图的SwiftUI讨论中解释了一些WWDC19布局的机制,但是他忽略了一些部分,我很难获得适当大小的视图。
是否有一种方法可以让视图告诉它的容器,它没有提出任何空间要求,但是它将使用它所提供的所有空间?另一种说法是容器应该拥抱其子视图。
具体的例子,我想要类似于c:
如果有一些Text
在VStack
中,如a),则VStack
将采用它的宽度到最宽的子视图。
如果您像在b中一样添加一个Rectangle
,它将尽可能地展开,直到VStack
填充它的容器为止。
这表明Text
s和Rectangle
s在布局上属于不同的类别,Text
有固定的大小,而Rectangle
是贪婪的。但是,如果我要制作自己的View
**?**,如何与容器进行通信呢?
我真正想要达到的结果是( c)。当VStack确定它的大小时,它应该忽略矩形(或我的自定义视图),然后一旦它这样做了,它应该告诉矩形,或者我的自定义视图,它可以有多少空间。
考虑到SwiftUI似乎是自下而上的布局,也许这是不可能的,但似乎应该有some
的方法来实现这一点。
发布于 2019-06-29 22:52:32
没有修饰符(AFAIK)来完成这一任务,所以我的方法如下。如果这是您要经常使用的东西,那么创建您自己的修饰符可能是值得的。
还请注意,这里我使用的是标准首选项,但锚首选项甚至更好。这是一个很难解释的话题。我写了一篇文章,你可以在这里查看:https://swiftui-lab.com/communicating-with-the-view-tree-part-1/
您可以使用下面的代码来完成您想要的任务。
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)])
}
}
}
发布于 2019-07-02 03:26:22
所以我找到了一种方法。首先,我试着用不同的配置在视图周围放置垫片,试图把它推到一起,但那是行不通的。然后,我意识到我也许可以使用.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)
}
}
蓝色的视图和所有的颜色背景,当然只是为了让它更容易看到。此代码生成以下内容:
https://stackoverflow.com/questions/56822791
复制