SwiftUI之 VStack、 HStack、 ZStack

在 SwiftUI 中,我们会经常使用到 VStackHStackZStack 来帮助我们进行布局。

VStack

VStack中的子视图都将按照垂直方向进行排列。

例如:

1
2
3
4
5
VStack {
Image(systemName: "globe")
Text("Hello, World!")
.font(.body)
}

此时的布局效果如下:

HStack

VStack 类似,不过 HStack是将子视图按照水平方向 进行排列。

类似地,将上面示例代码中的VStack 改为HStack :

1
2
3
4
5
HStack {
Image(systemName: "globe")
Text("Hello, World!")
.font(.body)
}

效果如下:

对于 VStackHStack 而言,都可以设置它们子视图之前的间距spacing 和对齐方式alignment

区别在于,VStack 的对齐方式有:

  • center:居中对齐;
  • leading :左对齐;
  • trailing : 右对齐。

HStack 的对齐方式有:

  • center :居中对齐;
  • top :顶部对齐;
  • bottom:底部对齐。
1
2
3
4
5
VStack(alignment: .leading, spacing: 10) {
Image(systemName: "globe")
Text("Hello, World!")
.font(.body)
}
1
2
3
4
5
HStack(alignment: .top, spacing: 10) {
Image(systemName: "globe")
Text("Hello, World!")
.font(.body)
}

ZStack

ZStack 是让子视图按照Z轴方向 堆叠排列。

1
2
3
4
5
6
7
8
ZStack {
Image("avatar")
.resizable()
.frame(width: 200, height: 200)
Text("Hello, World!")
.font(.body)
.foregroundStyle(.white)
}

效果如下:

ZStack 只能设置对齐方式alignment,它的对齐方式包括:

  • top:顶部对齐;
  • bottom:底部对齐;
  • center:居中对齐;
  • leading:左对齐;
  • trailing: 右对齐;
  • topLeading:左上角对齐;
  • topTrailing:右上角对齐;
  • bottomLeading:左下角对齐;
  • bottomTrailing: 右下角对齐。

布局示例

VStack
1
2
3
4
5
6
7
8
9
10
11
struct VStackContentView: View {
var body: some View {
// 左对齐,上下间距为10
VStack(alignment: .leading, spacing: 10) {
ForEach(0...10, id: \.self) {
Text("选项\($0)")
Divider()
}
}.padding(10)
}
}
HStack
1
2
3
4
5
6
7
8
9
10
11
struct HStackContentView: View {
var title: String = "朋友圈"
var body: some View {
HStack(alignment: .center, spacing: 10) {
Text(title)
Spacer()
Image(systemName: "chevron.right")
}
.padding(10)
}
}
ZStack
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct ZStackContentView: View {
// ZStack 实现头像置于背景之上的效果
var body: some View {
ZStack {
Image("bg")
.resizable()
.scaledToFit()
.frame(height: 300)
Image("avatar")
.resizable()
.frame(width: 100, height: 100)
.clipShape(Circle()) // 圆形头像设置
}
}
}
VStack、 HStack和 ZStack 一起使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct LayoutDemo: View {
var options = ["朋友圈", "发现", "游戏", "更多"]
var body: some View {
VStack {
ZStackContentView()
VStack {
ForEach(options, id: \.self) { title in
HStackContentView(title: title)
Divider()
}
}
}
}
}
ContentView
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
struct ContentView: View {
@State var selectedSeg:Int = 3
private let segmentArr = ["VStack", "HStack", "ZStack", "Layout"]

var body: some View {
VStack(spacing: 20) {
Picker(selection: $selectedSeg) {
ForEach(0 ..< segmentArr.count) {
Text(segmentArr[$0]).tag($0)
}
} label: {

}
.pickerStyle(.segmented) //设置选择器的样式
// 根据选择器绑定值的变化不同,显示不同的布局视图
switch selectedSeg {
case 0:
VStackContentView()
case 1:
HStackContentView()
Divider()
case 2:
ZStackContentView()
case 3:
LayoutDemo()
default:
Spacer()
}
Spacer()
}
}
}

效果如下: