在 SwiftUI 中拥抱子视图 [英] Hug subviews in SwiftUI
问题描述
Dave Abrahams 在他关于自定义视图的 WWDC19 演讲中解释了 SwiftUI 布局的一些机制,但他遗漏了一些内容,我无法正确调整视图的大小.
Dave Abrahams explained some of the mechanics of SwiftUI layouts in his WWDC19 talk about Custom Views, but he left out some bits and I have trouble getting my views properly sized.
有没有办法让 View 告诉它的容器它没有产生任何空间需求,但它会使用它给定的所有空间?另一种说法是容器应该拥抱它的子视图.
具体的例子,我想要类似 c:
Concrete example, I want something like c:
如果你在 VStack
中有一些 Text
就像在 a) 中一样,VStack
将采用它的宽度到最宽的子视图.
If you have some Text
s inside a VStack
like in a), the VStack
will adopt it's width to the widest subview.
如果你在 b) 中添加一个 Rectangle
,它会尽可能地扩展,直到 VStack
填满 它的 容器.
If you add a Rectangle
though as in b), it will expand as much as it can, until the VStack
fills its container.
这表明Text
s和Rectangle
s在布局上属于不同的类别,Text
有固定大小和Rectangle
是贪婪的.但是,如果我正在制作自己的View
,我如何将其传达给我的容器?
This indicates that Text
s and Rectangle
s are in different categories when it comes to layout, Text
has a fixed size and a Rectangle
is greedy. But how can I communicate this to my container if I'm making my own View
?
我真正想要达到的结果是 c).VStack 在确定其大小时应该忽略 Rectangle(或我的自定义视图),然后一旦完成,然后它应该告诉 Rectangle 或我的自定义视图它可以有多少空间.
The result I actually want to achieve is c). VStack should ignore Rectangle (or my custom view) when it determines its size, and then once it has done that, then it should tell Rectangle, or my custom view, how much space it can have.
鉴于 SwiftUI 似乎自下而上布局,也许这是不可能的,但似乎应该有some
方法来实现这一点.
Given that SwiftUI seems to layout bottom-up, maybe this is impossible, but it seems that there should be some
way to achieve this.
推荐答案
没有修饰符 (AFAIK) 来实现这一点,所以这是我的方法.如果这是您经常使用的东西,可能值得创建您自己的修饰符.
There is no modifier (AFAIK) to accomplish this, so here's my approach. If this is something you are going to use too often, it could be worth creating your own modifier.
另请注意,这里我使用的是标准首选项,但锚点首选项更好.在这里解释是一个沉重的话题.我写了一篇文章,你可以在这里查看:https://swiftui-lab.com/communicating-with-the-view-tree-part-1/
Also note that here I am using standard preferences, but anchor preferences are even better. It is a heavy topic to explain here. I've written an article that you can check here: https://swiftui-lab.com/communicating-with-the-view-tree-part-1/
您可以使用下面的代码来完成您要查找的内容.
You can use the code below to accomplish what you are looking for.
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)])
}
}
}
这篇关于在 SwiftUI 中拥抱子视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!