如何将 VStack 拆分为两个子视图,第二个子视图的高度是第一个子视图的两倍?

Posted

技术标签:

【中文标题】如何将 VStack 拆分为两个子视图,第二个子视图的高度是第一个子视图的两倍?【英文标题】:How can I split VStack to two sub view with double height of second sub view than first sub view? 【发布时间】:2019-07-04 19:14:11 【问题描述】:

我刚开始使用 SwiftUI,似乎 VStack 和 HStack 与 web 中的 flex box 非常相似。在 web 上,很容易使用 flex 将两个子视图拆分为高度权重

<div id="parent" style="display: flex; flex-direction: column; height: 300px">
  <div id="subA" style="flex: 1; background-color: red">Subview A</div>
  <div id="subB" style="flex: 2; background-color: yellow">Subview B</div>
</div>

我想知道在 swiftUI 上是否也可以。

VStack 
    VStack 
        Text("Subview A")
     // Subview A with height 100
        .background(Color.red)
    VStack 
        Text("Subview B")
     // Subview B with height 200
        .background(Color.yellow)

    .frame(height: 300, alignment: .center)

我该如何实现?

【问题讨论】:

【参考方案1】:

更新 #2:

感谢来自@kontiki 的answer and code,以下是使用此已弃用 方法的简单方法:

声明:

@State private var rect: CGRect = CGRect()

然后创建这个:

struct GeometryGetter: View 
    @Binding var rect: CGRect

    var body: some View 
        GeometryReader  geometry in
            Group  () -> ShapeView<Rectangle, Color> in
                DispatchQueue.main.async 
                    self.rect = geometry.frame(in: .global)
                
                return Rectangle().fill(Color.clear)
            
        
    

(对于那些熟悉 UIKit 的人,您基本上在父视图中创建一个不可见的 CALayerUIView 并将其框架传递给子视图 - 抱歉在技术上不是 100%准确,但请记住,这不是UIKit 堆栈。)

现在您有了父框架,您可以将它用作它的百分比(或“相对”)的基础。在这个问题中,有一个嵌套的 VStack 在另一个内部,您希望较低的 Text 是顶部的垂直大小的两倍。在这个答案的情况下,将您的 `ContentView 调整为:

struct ContentView : View 
    @State private var rect: CGRect = CGRect()
    var body: some View 
        VStack (spacing: 0) 
            RedView().background(Color.red)
                .frame(height: rect.height * 0.25)
            YellowView()
        
        .background(GeometryGetter(rect: $rect))
    


更新 #1:

从 beta 4 开始,此方法已弃用。 改为 relativeHeightrelativeWidth、relativeSizehave all been deprecated. Useframeinstead. If you want *relatve* sizing based on aView's parent, use GeometryReader`。 (见this question。)


原帖:

这就是你想要的。请记住,没有修饰符,一切都是居中的。此外,relativeHeight 似乎(至少对某些人来说)不是很直观。关键是要记住,在VSTack 中,父级占屏幕的 50%,因此 50% 的 50% 实际上是 25%。

或者,您可以指定frame 高度(让宽度占据整个屏幕)。但是您的示例表明,无论实际屏幕尺寸是多少,您都希望红色视图占整个屏幕的 25%。

struct RedView: View 
    var body: some View 
        ZStack 
            Color.red
            Text("Subview A")
        
    

struct YellowView: View 
    var body: some View 
        ZStack 
            Color.yellow
            Text("Subview B")
        
    

struct ContentView : View 
    var body: some View 
        VStack (spacing: 0) 
            RedView().background(Color.red).relativeHeight(0.50)
            YellowView()
        
    

【讨论】:

那么你的意思是用 VStack 作为子视图是不可能的吗? 我不确定你的意思。我的ContentView 一个`VStack`。 啊,没关系。当然,这是一个“基地”。 RedViewYellowView 没有理由不能包含 VStack 而不是普通的 Text。在运行时SwiftUI will compress them into a single View`。 真正的部分是了解将修饰符放置在何处(以及以什么顺序)。 我的意思是您的RedViewYellowView 基于ZStack,但有时我需要使用VStack 作为子视图,其中包含多个文本和按钮。上面只有一个Text的例子只是例子 我还尝试将relativeHeight(0.50) 应用于VStack,但结果出乎意料,正如您提到的50% of 50%。这是苹果还需要解决的问题吗?

以上是关于如何将 VStack 拆分为两个子视图,第二个子视图的高度是第一个子视图的两倍?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 VStack 中为子视图排列底部文本

如何将两个不同的ListAPIView转换为单个ModelViewSet

在 IOS 中使用自动布局在邻居之间居中视图

参考模态中的第二个子视图

UIScrollView 如何将充当容器的子视图约束到所有其他视图?

iOS:将子视图添加到倒数第二个位置