SwiftUI 布局容器详解
SwiftUI 提供了多种布局容器,每种都有特定的用途和行为。以下是对主要布局容器的全面详解:
一、基础布局容器
1. VStack - 垂直堆栈
swift
VStack(alignment: .leading, spacing: 10) {
Text("顶部")
Text("中部")
Text("底部")
}
- 功能:垂直排列子视图
- 参数 :
alignment:水平对齐方式(.leading,.center,.trailing)spacing:子视图间距
- 布局特性:根据子视图大小决定自身高度
2. HStack - 水平堆栈
swift
HStack(alignment: .top, spacing: 20) {
Text("左")
Text("中")
Text("右")
}
- 功能:水平排列子视图
- 参数 :
alignment:垂直对齐方式(.top,.center,.bottom,.firstTextBaseline,.lastTextBaseline)spacing:子视图间距
3. ZStack - 重叠堆栈
swift
ZStack(alignment: .topLeading) {
Rectangle()
.fill(Color.blue)
.frame(width: 200, height: 200)
Text("覆盖文本")
.foregroundColor(.white)
}
- 功能:子视图重叠排列
- 参数 :
alignment:对齐方式,控制所有子视图的共同对齐点
- 渲染顺序:后添加的视图在上层
二、惰性布局容器(Lazy Containers)
4. LazyVStack - 惰性垂直堆栈
swift
ScrollView {
LazyVStack(pinnedViews: .sectionHeaders) {
ForEach(0..<1000) { index in
Text("行 \(index)")
.frame(height: 50)
}
}
}
- 特性:仅渲染可见区域的视图,提高性能
- 参数 :
pinnedViews:固定视图(.sectionHeaders,.sectionFooters)
- 使用场景:长列表,性能敏感场景
5. LazyHStack - 惰性水平堆栈
swift
ScrollView(.horizontal) {
LazyHStack {
ForEach(0..<100) { index in
Text("列 \(index)")
.frame(width: 100)
}
}
}
6. LazyVGrid - 惰性垂直网格
swift
let columns = [
GridItem(.fixed(100)),
GridItem(.flexible()),
GridItem(.adaptive(minimum: 50))
]
ScrollView {
LazyVGrid(columns: columns, spacing: 10) {
ForEach(0..<100) { index in
Color.blue
.frame(height: 100)
.overlay(Text("\(index)"))
}
}
.padding()
}
- GridItem类型 :
.fixed(CGFloat):固定宽度.flexible(minimum:, maximum:):灵活宽度.adaptive(minimum:, maximum:):自适应,尽可能多放置
7. LazyHGrid - 惰性水平网格
swift
let rows = [GridItem(.fixed(100)), GridItem(.fixed(100))]
ScrollView(.horizontal) {
LazyHGrid(rows: rows, spacing: 20) {
ForEach(0..<50) { index in
Color.red
.frame(width: 100)
}
}
}
三、特殊布局容器
8. ScrollView - 滚动视图
swift
ScrollView(.vertical, showsIndicators: true) {
VStack {
ForEach(0..<50) { index in
Text("项目 \(index)")
.frame(maxWidth: .infinity)
.padding()
.background(Color.gray.opacity(0.2))
}
}
}
- 滚动方向 :
.vertical,.horizontal - 参数 :
showsIndicators:是否显示滚动条
9. List - 列表
swift
List {
Section(header: Text("第一部分")) {
ForEach(1..<5) { index in
Text("行 \(index)")
}
}
Section(footer: Text("结束")) {
ForEach(5..<10) { index in
Text("行 \(index)")
}
}
}
.listStyle(.insetGrouped) // 多种样式可选
- 样式 :
.plain,.grouped,.insetGrouped,.sidebar - 特性:自带滚动、优化性能、支持分节
10. Form - 表单
swift
Form {
Section("个人信息") {
TextField("姓名", text: $name)
DatePicker("生日", selection: $birthday)
}
Section("设置") {
Toggle("通知", isOn: $notifications)
Slider(value: $volume, in: 0...1)
}
}
- 特性:自动适配平台样式,适合设置界面
11. NavigationStack (iOS 16+) - 导航栈
swift
NavigationStack(path: $path) {
List {
NavigationLink("详情", value: "detail")
NavigationLink("设置", value: "settings")
}
.navigationDestination(for: String.self) { value in
switch value {
case "detail":
DetailView()
case "settings":
SettingsView()
default:
EmptyView()
}
}
}
12. TabView - 标签视图
swift
TabView {
HomeView()
.tabItem {
Label("首页", systemImage: "house")
}
.tag(0)
ProfileView()
.tabItem {
Label("我的", systemImage: "person")
}
.tag(1)
}
.tabViewStyle(.automatic) // 或 .page(页面式)
13. Grid (iOS 16+) - 网格布局
swift
Grid {
GridRow {
Text("姓名")
Text("年龄")
Text("城市")
}
.font(.headline)
Divider()
.gridCellUnsizedAxes(.horizontal)
GridRow {
Text("张三")
Text("25")
Text("北京")
}
}
四、布局辅助视图
14. Spacer - 间距器
swift
HStack {
Text("左")
Spacer() // 将左右视图推向两端
Text("右")
}
VStack {
Text("顶部")
Spacer(minLength: 20) // 最小间距
Text("底部")
}
15. Divider - 分割线
swift
VStack {
Text("上部分")
Divider() // 水平分割线
Text("下部分")
}
16. Group - 分组容器
swift
VStack {
Group {
if condition {
Text("条件1")
} else {
Text("条件2")
}
}
.padding()
.background(Color.yellow)
}
- 作用 :
- 突破10个子视图限制
- 统一应用修饰符
- 条件逻辑分组
17. ViewBuilder - 视图构建器
swift
@ViewBuilder
func createView(showDetail: Bool) -> some View {
Text("基础")
if showDetail {
Text("详情")
Image(systemName: "star")
}
}
五、自定义布局容器
18. Layout 协议 (iOS 16+)
swift
struct MyCustomLayout: Layout {
func sizeThatFits(
proposal: ProposedViewSize,
subviews: Subviews,
cache: inout ()
) -> CGSize {
// 计算布局所需大小
CGSize(width: proposal.width ?? 300, height: 200)
}
func placeSubviews(
in bounds: CGRect,
proposal: ProposedViewSize,
subviews: Subviews,
cache: inout ()
) {
// 放置子视图
var point = bounds.origin
for subview in subviews {
subview.place(at: point, proposal: .unspecified)
point.x += 100
}
}
}
19. AnyLayout (iOS 16+)
swift
@State private var isVertical = true
var body: some View {
let layout = isVertical ? AnyLayout(VStackLayout()) : AnyLayout(HStackLayout())
layout {
Text("视图1")
Text("视图2")
}
}
六、布局修饰符
20. frame - 尺寸约束
swift
Text("Hello")
.frame(
maxWidth: .infinity, // 最大宽度
minHeight: 50, // 最小高度
alignment: .center // 对齐方式
)
21. padding - 内边距
swift
Text("内容")
.padding() // 所有方向
.padding(.horizontal, 10) // 水平方向
.padding(.top, 20) // 顶部
.padding(EdgeInsets(top: 10, leading: 20, bottom: 10, trailing: 20))
22. position & offset - 位置调整
swift
Text("绝对定位")
.position(x: 100, y: 100) // 相对于父视图
Text("相对偏移")
.offset(x: 10, y: -5) // 相对当前位置
七、布局优先级
23. 布局优先级
swift
HStack {
Text("短文本")
.layoutPriority(1) // 高优先级,先分配空间
Text("这是一个非常长的文本,可能会被压缩")
.layoutPriority(0) // 低优先级
}
.frame(width: 200)
八、布局选择指南
| 容器 | 适用场景 | 性能特点 |
|---|---|---|
| VStack/HStack | 简单布局,子视图数量少 | 立即布局所有子视图 |
| LazyVStack/LazyHStack | 长列表,滚动视图 | 惰性加载,高性能 |
| List | 数据列表,需要交互 | 高度优化,支持选择、删除等 |
| Grid/LazyVGrid | 网格布局,瀑布流 | 灵活的多列布局 |
| ZStack | 重叠布局,层叠效果 | 适合覆盖、浮动元素 |
| ScrollView | 自定义滚动内容 | 需要手动管理性能 |
九、最佳实践
- 选择合适的容器:根据需求选择最合适的布局容器
- 避免过度嵌套:简化布局层级,提高性能
- 使用惰性容器:处理大量数据时使用Lazy容器
- 利用Spacer:灵活控制视图间距
- 组合使用:合理组合多个容器实现复杂布局
- 测试多尺寸:在不同设备尺寸和方向上测试布局
这些容器可以灵活组合使用,创造出各种复杂的用户界面。掌握这些布局容器的特性和适用场景,是成为SwiftUI布局专家的关键。