布局基础
SwiftUI 提供了一套声明式的布局系统,通过组合不同的容器视图(Container Views)来构建复杂的用户界面。本文详细总结了 SwiftUI 布局基础的核心概念和组件。
堆栈视图 (Stack Views)
堆栈视图是 SwiftUI 布局的基础,用于在水平、垂直或深度(Z 轴)方向上排列视图。
HStack, VStack, ZStack
- HStack: 水平排列子视图。
- VStack: 垂直排列子视图。
- ZStack: 沿 Z 轴叠加子视图(后添加的视图在顶层)。
struct StackExample: View {
var body: some View {
VStack(spacing: 20) {
// 水平排列
HStack {
Text("Leading")
Spacer()
Text("Trailing")
}
// 叠加排列
ZStack {
Circle().fill(Color.blue).frame(width: 50, height: 50)
Text("1").foregroundColor(.white)
}
}
}
}常用修饰符
alignment: 设置子视图在堆栈中的对齐方式(如.leading,.center,.top)。spacing: 设置子视图之间的间距。
懒加载堆栈 (Lazy Stacks)
当需要展示大量数据时,使用标准堆栈会一次性加载所有视图,影响性能。懒加载堆栈仅在视图即将出现在屏幕上时才进行渲染。
- LazyHStack: 水平方向的懒加载堆栈,通常配合
ScrollView(.horizontal)使用。 - LazyVStack: 垂直方向的懒加载堆栈,通常配合
ScrollView使用。
ScrollView {
LazyVStack(alignment: .leading) {
ForEach(1...100, id: \.self) { item in
Text("Row \(item)")
}
}
}网格布局 (Grids)
SwiftUI 提供了两种网格布局方式:静态网格 (Grid) 和懒加载网格 (LazyGrid)。
Grid (iOS 16+)
Grid 是一个容器视图,用于创建二维布局。它会立即加载所有子视图,适合视图数量较少且需要精确对齐的场景。使用 GridRow 定义行。
Grid {
GridRow {
Text("Top Left")
Text("Top Right")
}
Divider()
GridRow {
Text("Bottom Left")
Text("Bottom Right")
}
}- GridRow: 代表网格中的一行。
- gridCellColumns(_:): 让某个单元格跨越多列。
LazyVGrid & LazyHGrid
适用于大量数据的网格布局,仅渲染可见区域的单元格。需要配合 GridItem 定义列(或行)的布局行为。
- GridItem: 定义网格的列(对于
LazyVGrid)或行(对于LazyHGrid)。支持.fixed,.flexible,.adaptive三种尺寸模式。
struct LazyGridExample: View {
let columns = [
GridItem(.flexible()),
GridItem(.flexible())
]
var body: some View {
ScrollView {
LazyVGrid(columns: columns, spacing: 20) {
ForEach(0..<20) { index in
Text("Item \(index)")
.frame(height: 50)
.background(Color.gray.opacity(0.2))
}
}
}
}
}弹性空间与分割线
Spacer
Spacer 是一个灵活的空间视图,它会沿着堆栈的主轴方向尽可能地扩展,从而推挤其他视图。
- 在
HStack中使用Spacer可以将视图推向两端。 minLength: 可以指定最小长度。
Divider
Divider 是一条细线,用于在视觉上分隔内容。
- 在
HStack中是垂直线。 - 在
VStack中是水平线。
几何读取器 (GeometryReader)
GeometryReader 是一个容器视图,它将其自身的大小和坐标空间作为 GeometryProxy 传递给闭包。这使得子视图可以根据父视图的大小进行动态布局。
GeometryReader { geometry in
HStack(spacing: 0) {
Text("Left")
.frame(width: geometry.size.width * 0.5)
.background(Color.green)
Text("Right")
.frame(width: geometry.size.width * 0.5)
.background(Color.orange)
}
}
.frame(height: 50)GeometryReader 默认会尽可能占用所有可用空间,可能会影响父视图的布局。
自适应布局 (ViewThatFits)
ViewThatFits (iOS 16+) 允许你提供一组视图,它会自动选择第一个能够完整放入可用空间的视图。这对于适配不同屏幕尺寸或动态内容非常有用。
ViewThatFits {
// 优先尝试水平排列(如果宽度足够)
HStack {
Text("Long Text Content")
Text("More Content")
}
// 如果宽度不够,回退到垂直排列
VStack {
Text("Long Text Content")
Text("More Content")
}
}自定义布局 (Layout Protocol)
对于标准容器无法满足的复杂布局需求,SwiftUI 提供了 Layout 协议 (iOS 16+)。通过实现 sizeThatFits 和 placeSubviews 方法,可以完全自定义视图的排列逻辑。这是一个高级特性,通常用于构建通用的布局容器。
总结
- 使用 Stacks (
HStack,VStack,ZStack) 处理基本布局。 - 使用 Lazy Stacks 处理长列表性能优化。
- 使用 Grid 处理静态二维对齐,使用 LazyGrid 处理大量数据的网格。
- 使用 Spacer 和 Divider 控制间距和分隔。
- 使用 GeometryReader 获取尺寸信息。
- 使用 ViewThatFits 实现内容自适应。
上次更新于