187

鉴于此代码:

import SwiftUI

struct ContentView: View {
  var body: some View {
    VStack(alignment: .leading) {
      Text("Title")
        .font(.title)

      Text("Content")
        .lineLimit(nil)
        .font(.body)

      Spacer()
    }
    .background(Color.red)
  }
}

#if DEBUG
struct ContentView_Previews : PreviewProvider {
  static var previews: some View {
    ContentView()
  }
}
#endif

结果是这个界面:

预览

VStack即使标签/文本组件不需要全宽,我如何才能填充屏幕的宽度?


我发现的一个技巧是在结构中插入一个 HStack,如下所示:

VStack(alignment: .leading) {
  HStack {
    Spacer()
  }
  Text("Title")
    .font(.title)

  Text("Content")
    .lineLimit(nil)
    .font(.body)

  Spacer()
}

这会产生所需的设计:

期望的输出

有没有更好的办法?

4

16 回答 16

301

尝试使用.frame带有以下选项的修饰符:

.frame(
      minWidth: 0,
      maxWidth: .infinity,
      minHeight: 0,
      maxHeight: .infinity,
      alignment: .topLeading
    )
struct ContentView: View {
  var body: some View {
    VStack(alignment: .leading) {
      Text("Hello World")
        .font(.title)
      Text("Another")
        .font(.body)
      Spacer()
    }
    .frame(
      minWidth: 0,
      maxWidth: .infinity,
      minHeight: 0,
      maxHeight: .infinity,
      alignment: .topLeading
    )
    .background(Color.red)
  }
}

这被描述为一个灵活的框架(请参阅文档),它将拉伸以填满整个屏幕,并且当它有额外的空间时,它会将其内容居中放置在其中。

于 2019-06-07T03:31:08.440 回答
55

以下是一种可行且可能更直观的替代堆叠安排:

struct ContentView: View {
    var body: some View {
        HStack() {
            VStack(alignment: .leading) {
                Text("Hello World")
                    .font(.title)
                Text("Another")
                    .font(.body)
                Spacer()
            }
            Spacer()
        }.background(Color.red)
    }
}

Spacer()如有必要,还可以通过删除 's 轻松地重新定位内容。

添加/移除垫片以改变位置

于 2019-06-07T14:43:19.753 回答
46

在 Swift 5.2 和 iOS 13.4 中,根据您的需要,您可以使用以下示例之一来调整您VStack的顶级领先约束和全尺寸框架。

请注意,下面的代码片段都导致相同的显示,但不保证在调试视图层次结构时可能出现的有效框架VStack或元素数量。View


一、使用frame(minWidth:idealWidth:maxWidth:minHeight:idealHeight:maxHeight:alignment:)方法

最简单的方法是设置VStack最大宽度和高度的框架,并在以下位置传递所需的对齐方式frame(minWidth:idealWidth:maxWidth:minHeight:idealHeight:maxHeight:alignment:)

struct ContentView: View {

    var body: some View {
        VStack(alignment: .leading) {
            Text("Title")
                .font(.title)
            Text("Content")
                .font(.body)
        }
        .frame(
            maxWidth: .infinity,
            maxHeight: .infinity,
            alignment: .topLeading
        )
        .background(Color.red)
    }

}

2.使用Spacers强制对齐

您可以将您的VStackinside 嵌入一个完整尺寸HStack并使用 trailing 和 bottom Spacers 来强制您的VStack顶部前导对齐:

struct ContentView: View {

    var body: some View {
        HStack {
            VStack(alignment: .leading) {
                Text("Title")
                    .font(.title)
                Text("Content")
                    .font(.body)

                Spacer() // VStack bottom spacer
            }

            Spacer() // HStack trailing spacer
        }
        .frame(
            maxWidth: .infinity,
            maxHeight: .infinity
        )
        .background(Color.red)
    }

}

3. 使用ZStack全尺寸背景View

此示例显示如何将您嵌入VStackZStack具有顶部前导对齐的内部。请注意Color视图如何用于设置最大宽度和高度:

struct ContentView: View {

    var body: some View {
        ZStack(alignment: .topLeading) {
            Color.red
                .frame(maxWidth: .infinity, maxHeight: .infinity)

            VStack(alignment: .leading) {
                Text("Title")
                    .font(.title)
                Text("Content")
                    .font(.body)
            }
        }
    }

}

4.使用GeometryReader

GeometryReader有以下声明

将其内容定义为自身大小和坐标空间的函数的容器视图。[...] 这个视图返回一个灵活的首选大小到它的父布局。

下面的代码片段显示了如何使用顶级领先约束和全尺寸框架GeometryReader对齐您的:VStack

struct ContentView : View {

    var body: some View {
        GeometryReader { geometryProxy in
            VStack(alignment: .leading) {
                Text("Title")
                    .font(.title)
                Text("Content")
                    .font(.body)
            }
            .frame(
                width: geometryProxy.size.width,
                height: geometryProxy.size.height,
                alignment: .topLeading
            )
        }
        .background(Color.red)
    }

}

五、使用overlay(_:alignment:)方法

如果你想VStack在现有的 full size 上对齐你的顶级领先约束View,你可以使用overlay(_:alignment:)方法:

struct ContentView: View {

    var body: some View {
        Color.red
            .frame(
                maxWidth: .infinity,
                maxHeight: .infinity
            )
            .overlay(
                VStack(alignment: .leading) {
                    Text("Title")
                        .font(.title)
                    Text("Content")
                        .font(.body)
                },
                alignment: .topLeading
            )
    }

}

展示:

于 2020-04-26T16:46:39.990 回答
33

有一个更好的方法!

VStack填充其父级的宽度,您可以使用 aGeometryReader并设置框架。(.relativeWidth(1.0)应该可以,但现在显然不行)

struct ContentView : View {
    var body: some View {
        GeometryReader { geometry in
            VStack {
                Text("test")
            }
                .frame(width: geometry.size.width,
                       height: nil,
                       alignment: .topLeading)
        }
    }
}

要设置VStack实际屏幕的宽度,您可以UIScreen.main.bounds.width在设置框架时使用而不是使用 a GeometryReader,但我想您可能想要父视图的宽度。

此外,这种方式还有一个额外的好处,VStack即如果您在.HStackSpacer()VStack

更新 - 没有更好的方法!

在检查了接受的答案后,我意识到接受的答案实际上不起作用!乍一看似乎可以工作,但是如果您将 更新VStack为具有绿色背景,您会发现VStack仍然是相同的宽度。

struct ContentView : View {
    var body: some View {
        NavigationView {
            VStack(alignment: .leading) {
                Text("Hello World")
                    .font(.title)
                Text("Another")
                    .font(.body)
                Spacer()
                }
                .background(Color.green)
                .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading)
                .background(Color.red)
        }
    }
}

这是因为.frame(...)实际上是在视图层次结构中添加了另一个视图,并且该视图最终填满了屏幕。但是,VStack仍然没有。

这个问题在我的回答中似乎也一样,可以使用与上述相同的方法进行检查(在 . 之前和之后放置不同的背景颜色.frame(...)。似乎实际扩大的唯一方法VStack是使用垫片:

struct ContentView : View {
    var body: some View {
        VStack(alignment: .leading) {
            HStack{
                Text("Title")
                    .font(.title)
                Spacer()
            }
            Text("Content")
                .lineLimit(nil)
                .font(.body)
            Spacer()
        }
            .background(Color.green)
    }
}
于 2019-06-07T05:08:59.653 回答
11

我设法解决问题的最简单方法是使用 ZStack + .edgesIgnoringSafeArea(.all)

struct TestView : View {

    var body: some View {
        ZStack() {
            Color.yellow.edgesIgnoringSafeArea(.all)
            VStack {
                Text("Hello World")
            }
        }
    }
}
于 2019-11-26T19:18:15.197 回答
6

用这个

.edgesIgnoringSafeArea(.all)
于 2019-11-07T21:28:59.230 回答
6

一个好的解决方案,没有“装置”是被遗忘的ZStack

ZStack(alignment: .top){
    Color.red
    VStack{
        Text("Hello World").font(.title)
        Text("Another").font(.body)
    }
}

结果:

在此处输入图像描述

于 2020-05-11T14:52:26.423 回答
5

您可以使用GeometryReader

几何阅读器

代码:

struct ContentView : View {
    var body: some View {
        GeometryReader { geometry in
            VStack {
               Text("Turtle Rock").frame(width: geometry.size.width, height: geometry.size.height, alignment: .topLeading).background(Color.red)
            }
        }
    }
}

您的输出如下:

在此处输入图像描述

于 2019-06-07T06:29:37.337 回答
5

另一种选择是将其中一个子视图放在 an 内HStack并在其后放置 a Spacer()

struct ContentView : View {
    var body: some View {
        VStack(alignment: .leading) {

            HStack {
                Text("Title")
                    .font(.title)
                    .background(Color.yellow)
                Spacer()
            }

            Text("Content")
                .lineLimit(nil)
                .font(.body)
                .background(Color.blue)

            Spacer()
            }

            .background(Color.red)
    }
}

导致 :

VStack 中的 HStack

于 2019-06-07T14:19:19.217 回答
4

这是一段有用的代码:

extension View {
    func expandable () -> some View {
        ZStack {
            Color.clear
            self
        }
    }
}

比较有和没有.expandable()修饰符的结果:

Text("hello")
    .background(Color.blue)

-

Text("hello")
    .expandable()
    .background(Color.blue)

在此处输入图像描述

于 2019-12-27T21:56:25.210 回答
3

这对我有用(ScrollView(可选)因此可以根据需要添加更多内容,以及居中的内容):

import SwiftUI

struct SomeView: View {
    var body: some View {
        GeometryReader { geometry in
            ScrollView(Axis.Set.horizontal) {
                HStack(alignment: .center) {
                    ForEach(0..<8) { _ in
                        Text("")
                    }
                }.frame(width: geometry.size.width, height: 50)
            }
        }
    }
}

// MARK: - Preview

#if DEBUG
struct SomeView_Previews: PreviewProvider {
    static var previews: some View {
        SomeView()
    }
}
#endif

结果

居中

于 2019-07-26T15:59:21.757 回答
3

我知道这对每个人都不起作用,但我觉得有趣的是,只需添加一个 Divider 就可以解决这个问题。

struct DividerTest: View {
var body: some View {
    VStack(alignment: .leading) {
        Text("Foo")
        Text("Bar")
        Divider()
    }.background(Color.red)
  }
}
于 2019-11-27T23:22:02.767 回答
2

您可以在方便的扩展中使用 GeometryReader 来填充父级

extension View {
    func fillParent(alignment:Alignment = .center) -> some View {
        return GeometryReader { geometry in
            self
                .frame(width: geometry.size.width,
                       height: geometry.size.height,
                       alignment: alignment)
        }
    }
}

所以使用请求的例子,你得到

struct ContentView : View {
    var body: some View {
        VStack(alignment: .leading) {
            Text("Title")
                .font(.title)

            Text("Content")
                .lineLimit(nil)
                .font(.body)
        }
        .fillParent(alignment:.topLeading)
        .background(Color.red)
    }
}

(注意不再需要垫片)

在此处输入图像描述

于 2020-01-19T17:15:46.687 回答
2

在此处输入图像描述

登录页面设计使用SwiftUI

import SwiftUI

struct ContentView: View {

    @State var email: String = "william@gmail.com"
    @State var password: String = ""
    @State static var labelTitle: String = ""


    var body: some View {
        VStack(alignment: .center){
            //Label
            Text("Login").font(.largeTitle).foregroundColor(.yellow).bold()
            //TextField
            TextField("Email", text: $email)
                .textContentType(.emailAddress)
                .foregroundColor(.blue)
                .frame(minHeight: 40)
                .background(RoundedRectangle(cornerRadius: 10).foregroundColor(Color.green))

            TextField("Password", text: $password) //Placeholder
                .textContentType(.newPassword)
                .frame(minHeight: 40)
                .foregroundColor(.blue) // Text color
                .background(RoundedRectangle(cornerRadius: 10).foregroundColor(Color.green))

            //Button
            Button(action: {

            }) {
                HStack {
                    Image(uiImage: UIImage(named: "Login")!)
                        .renderingMode(.original)
                        .font(.title)
                        .foregroundColor(.blue)
                    Text("Login")
                        .font(.title)
                        .foregroundColor(.white)
                }


                .font(.headline)
                .frame(minWidth: 0, maxWidth: .infinity)
                .background(LinearGradient(gradient: Gradient(colors: [Color("DarkGreen"), Color("LightGreen")]), startPoint: .leading, endPoint: .trailing))
                .cornerRadius(40)
                .padding(.horizontal, 20)

                .frame(width: 200, height: 50, alignment: .center)
            }
            Spacer()

        }.padding(10)

            .frame(minWidth: 0, idealWidth: .infinity, maxWidth: .infinity, minHeight: 0, idealHeight: .infinity, maxHeight: .infinity, alignment: .top)
            .background(Color.gray)

    }

}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
于 2020-02-19T13:47:22.167 回答
1

预览图像

方式 1 -> 使用 MaxWidth 和 MaxHeight

import SwiftUI

struct SomeView: View {
    var body: some View {
        VStack {
            Text("Hello, World!")
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(.red)
    }
}

struct SomeView_Previews: PreviewProvider {
    static var previews: some View {
        SomeView()
    }
}

方式 2 -> 使用主屏幕边界

import SwiftUI

struct SomeView: View {
    var body: some View {
        VStack {
            Text("Hello, World!")
        }
        .frame(maxWidth: UIScreen.main.bounds.width, maxHeight: UIScreen.main.bounds.height)
        .background(.red)
    }
}

struct SomeView_Previews: PreviewProvider {
    static var previews: some View {
        SomeView()
    }
}

方式 3 -> 使用几何阅读器

import SwiftUI

struct SomeView: View {
    var body: some View {
        GeometryReader { geometryReader in
            VStack {
                Text("Hello, World!")
            }
            .frame(maxWidth: geometryReader.size.width, maxHeight: geometryReader.size.height)
            .background(.red)
        }
    }
}

struct SomeView_Previews: PreviewProvider {
    static var previews: some View {
        SomeView()
    }
}

方式 4 -> 使用垫片

import SwiftUI

struct SomeView: View {
    var body: some View {
        VStack {
            Text("Hello, World!")
            HStack{
                Spacer()
            }
            Spacer()
        }
        .background(.red)
    }
}

struct SomeView_Previews: PreviewProvider {
    static var previews: some View {
        SomeView()
    }
}
于 2022-01-28T06:17:28.133 回答
0

这是另一种可以节省项目时间的方法:

与其他不可重用的答案相比,代码和可重用性要少得多!


extension View {
    
    var maxedOut: some View {
        
        return Color.clear
            .overlay(self, alignment: .center)

    }
    
    func maxedOut(color: Color = Color.clear, alignment: Alignment = Alignment.center) -> some View {
        
        return color
            .overlay(self, alignment: alignment)
        
    }
    
}

用例:

struct ContentView: View {

    var body: some View {

        Text("Hello, World!")
            .maxedOut
            .background(Color.blue)
        
        Text("Hello, World!")
            .maxedOut(color: Color.red)
  
    }
}

在此处输入图像描述

于 2021-04-18T09:37:36.880 回答