第4章:基础布局系统

3 阅读11分钟

Snip20260416_1.png

Snip20260416_2.png

示例代码都放这里啦,有需要的可以下载学习。swiftUIDemo

第4章:基础布局系统

4.1 垂直布局:VStack

VStack 介绍

VStack 是 SwiftUI 中用于垂直堆叠视图的容器,它会将子视图按垂直方向排列。VStack 是构建垂直布局的基础组件,适用于需要从上到下排列的界面元素。

基本用法


// 基本垂直栈

VStack {

    Text("第一行")

    Text("第二行")

    Text("第三行")

}

  


// 带间距和对齐的垂直栈

VStack(alignment: .leading, spacing: 20) {

    Text("左对齐")

    Text("第二行")

    Text("第三行")

}

.padding()

对齐方式

VStack 提供了三种主要的对齐方式:

  • .leading:左对齐

  • .center:居中对齐(默认)

  • .trailing:右对齐

  • .top.bottom:在嵌套布局中使用


// 不同对齐方式

VStack(alignment: .leading) {

    Text("左对齐")

    Text("这是一行更长的文本")

    Text("短文本")

}

.padding()

  


VStack(alignment: .center) {

    Text("居中对齐")

    Text("这是一行更长的文本")

    Text("短文本")

}

.padding()

  


VStack(alignment: .trailing) {

    Text("右对齐")

    Text("这是一行更长的文本")

    Text("短文本")

}

.padding()

嵌套 VStack

VStack 可以嵌套使用,创建更复杂的布局结构。


// 嵌套垂直栈

VStack(spacing: 10) {

    Text("标题")

        .font(.headline)

    

    VStack(alignment: .leading, spacing: 8) {

        Text("项目 1")

        Text("项目 2")

        Text("项目 3")

    }

    .padding()

    .background(Color.gray.opacity(0.1))

    .cornerRadius(8)

    

    Button("确认") {}

}

.padding()

适用场景

  • 表单布局:从上到下排列的输入字段

  • 列表项:垂直排列的内容块

  • 页面结构:标题、内容、按钮的垂直布局

  • 卡片式布局:垂直堆叠的信息卡片

性能考虑

  • VStack 会根据子视图的大小自动调整高度

  • 对于大量子视图,考虑使用 LazyVStack 来提高性能

  • 避免过深的嵌套,可能会影响渲染性能

4.2 水平布局:HStack

HStack 介绍

HStack 是 SwiftUI 中用于水平堆叠视图的容器,它会将子视图按水平方向排列。HStack 是构建水平布局的基础组件,适用于需要从左到右排列的界面元素。

基本用法


// 基本水平栈

HStack {

    Text("左侧")

    Text("中间")

    Text("右侧")

}

  


// 带间距和对齐的水平栈

HStack(alignment: .top, spacing: 20) {

    Text("顶部对齐")

    Text("这是一行\n多行文本")

    Text("短文本")

}

.padding()

对齐方式

HStack 提供了三种主要的对齐方式:

  • .top:顶部对齐

  • .center:居中对齐(默认)

  • .bottom:底部对齐

  • .leading.trailing:在嵌套布局中使用


// 不同对齐方式

HStack(alignment: .top) {

    Text("顶部对齐")

    Text("这是一行\n多行文本")

    Text("短文本")

}

.padding()

  


HStack(alignment: .center) {

    Text("居中对齐")

    Text("这是一行\n多行文本")

    Text("短文本")

}

.padding()

  


HStack(alignment: .bottom) {

    Text("底部对齐")

    Text("这是一行\n多行文本")

    Text("短文本")

}

.padding()

空间分配

HStack 可以使用 Spacer 来分配空间,实现更灵活的布局。


// 空间分配

HStack {

    Text("左侧")

    Spacer()  // 占据剩余空间

    Text("右侧")

}

.padding()

  


// 带比例的空间分配

HStack {

    Text("1/4 宽度")

        .frame(maxWidth: .infinity)

    Spacer()

    Text("1/4 宽度")

        .frame(maxWidth: .infinity)

    Spacer()

    Text("1/4 宽度")

        .frame(maxWidth: .infinity)

    Spacer()

    Text("1/4 宽度")

        .frame(maxWidth: .infinity)

}

.padding()

适用场景

  • 工具栏:水平排列的操作按钮

  • 列表项内容:左侧图标、中间文本、右侧箭头

  • 表单行:标签和输入框的水平排列

  • 导航栏:左侧返回按钮、中间标题、右侧操作按钮

性能考虑

  • HStack 会根据子视图的大小自动调整宽度

  • 对于大量子视图,考虑使用 LazyHStack 来提高性能

  • 注意水平空间不足时的布局行为,可能需要使用 ScrollView

4.3 层叠布局:ZStack

ZStack 介绍

ZStack 是 SwiftUI 中用于层叠视图的容器,它会将子视图按层叠方式排列,后面的视图会覆盖前面的视图。ZStack 是构建叠加效果的基础组件,适用于需要层级关系的界面元素。

基本用法


// 基本层叠

ZStack {

    Color.blue  // 背景

    Text("前景文本")

        .foregroundStyle(.white)

        .font(.largeTitle)

}

.frame(height: 200)

  


// 多层叠

ZStack {

    // 底层

    Rectangle()

        .fill(Color.yellow)

        .frame(width: 200, height: 200)

    

    // 中层

    Circle()

        .fill(Color.green)

        .frame(width: 150, height: 150)

    

    // 顶层

    Text("ZStack")

        .font(.headline)

}

对齐方式

ZStack 提供了多种对齐方式,可以精确控制子视图的位置:

  • .topLeading.top.topTrailing

  • .leading.center.trailing

  • .bottomLeading.bottom.bottomTrailing


// 不同对齐方式

ZStack(alignment: .topLeading) {

    Rectangle()

        .fill(Color.gray.opacity(0.2))

        .frame(width: 300, height: 200)

    

    Text("左上角")

        .padding(10)

}

  


ZStack(alignment: .center) {

    Rectangle()

        .fill(Color.gray.opacity(0.2))

        .frame(width: 300, height: 200)

    

    Text("居中")

}

  


ZStack(alignment: .bottomTrailing) {

    Rectangle()

        .fill(Color.gray.opacity(0.2))

        .frame(width: 300, height: 200)

    

    Text("右下角")

        .padding(10)

}

实际应用


// 带徽章的图标

ZStack(alignment: .topTrailing) {

    Image(systemName: "bell")

        .font(.system(size: 24))

    

    Circle()

        .fill(Color.red)

        .frame(width: 16, height: 16)

        .overlay {

            Text("3")

                .font(.system(size: 10))

                .foregroundStyle(.white)

        }

        .offset(x: 4, y: -4)

}

  


// 卡片覆盖效果

ZStack {

    RoundedRectangle(cornerRadius: 12)

        .fill(Color.white)

        .shadow(radius: 4)

        .frame(width: 300, height: 200)

    

    VStack {

        Text("卡片标题")

            .font(.headline)

        Text("卡片内容")

            .foregroundStyle(.secondary)

    }

    .padding()

    

    // 右上角标签

    Text("NEW")

        .font(.caption)

        .foregroundStyle(.white)

        .padding(4)

        .background(Color.blue)

        .cornerRadius(4)

        .offset(x: 45, y: -10)

}

适用场景

  • 带背景的文本:文本叠加在背景之上

  • 徽章效果:通知图标上的数字徽章

  • 卡片布局:带有覆盖元素的信息卡片

  • 复杂 UI 组件:需要多层叠加的自定义控件

  • 模态视图:半透明覆盖层

性能考虑

  • ZStack 会按照添加顺序渲染视图,后面的视图会覆盖前面的

  • 对于复杂的叠加效果,注意渲染性能

  • 考虑使用 offset 修饰符来微调子视图位置

4.4 间距与对齐

间距设置

间距是布局中的重要因素,它决定了视图之间的关系和视觉舒适度。


// VStack 间距

VStack(spacing: 16) {

    Text("项目 1")

    Text("项目 2")

    Text("项目 3")

}

  


// HStack 间距

HStack(spacing: 20) {

    Text("左")

    Text("中")

    Text("右")

}

  


// 嵌套栈的间距

VStack(spacing: 20) {

    Text("标题")

    

    HStack(spacing: 10) {

        Button("按钮 1") {}

        Button("按钮 2") {}

    }

    

    Text("底部文本")

}

对齐设置

对齐决定了视图在容器中的位置,影响整体布局的一致性。


// 垂直对齐

VStack(alignment: .leading) {

    Text("左对齐")

    Text("这是一行更长的文本")

}

  


// 水平对齐

HStack(alignment: .center) {

    Text("顶部")

        .font(.largeTitle)

    Text("底部")

        .font(.footnote)

}

  


// 层叠对齐

ZStack(alignment: .bottom) {

    Image(systemName: "photo")

        .resizable()

        .aspectRatio(contentMode: .fit)

        .frame(height: 200)

    

    Text("图片标题")

        .padding()

        .background(Color.black.opacity(0.5))

        .foregroundStyle(.white)

        .frame(maxWidth: .infinity, alignment: .center)

}

内边距与外边距

内边距(padding)和外边距是控制视图与其他元素之间空间的重要工具。


// 内边距

VStack {

    Text("带内边距的文本")

        .padding()  // 四周内边距

    

    Text("自定义内边距")

        .padding(.horizontal, 20// 水平内边距

        .padding(.vertical, 10)    // 垂直内边距

}

  


// 外边距

VStack {

    Text("带外边距的文本")

}

.padding()  // 给整个 VStack 添加内边距

  


// 组合使用

Text("文本")

    .padding(10// 内边距

    .background(Color.yellow)

    .padding(10// 外边距(看起来像内边距)

    .background(Color.blue)

适用场景

  • 表单设计:通过间距和对齐创建整齐的表单

  • 卡片布局:使用内边距和外边距创建视觉层次感

  • 响应式设计:根据不同屏幕尺寸调整间距

  • 可访问性:适当的间距提高内容的可读性

最佳实践

  • 保持一致的间距系统:使用统一的间距值(如 8、16、24 等)

  • 考虑内容的重要性:重要内容之间应有更大的间距

  • 响应式调整:在不同屏幕尺寸上调整间距

  • 测试不同设备:确保在各种设备上布局都美观

4.5 垫片:Spacer

Spacer 介绍

Spacer 是 SwiftUI 中用于占据剩余空间的视图,它会自动扩展以填充可用空间。Spacer 是实现灵活布局的重要工具,特别适用于需要将元素推到容器边缘的场景。

基本用法


// 水平布局中的 Spacer

HStack {

    Text("左侧")

    Spacer()  // 占据中间的所有空间

    Text("右侧")

}

.padding()

  


// 垂直布局中的 Spacer

VStack {

    Text("顶部")

    Spacer()  // 占据中间的所有空间

    Text("底部")

}

.frame(height: 200)

.padding()

灵活使用


// 顶部对齐

VStack {

    Text("标题")

    Spacer()

}

.frame(height: 200)

.padding()

  


// 底部对齐

VStack {

    Spacer()

    Text("底部文本")

}

.frame(height: 200)

.padding()

  


// 两端对齐

HStack {

    Text("左侧")

    Spacer()

    Text("中间")

    Spacer()

    Text("右侧")

}

.padding()

实际应用


// 工具栏布局

HStack {

    Button("返回") {

        print("返回")

    }

    

    Spacer()

    

    Text("页面标题")

    

    Spacer()

    

    Button("更多") {

        print("更多")

    }

}

.padding()

.background(Color(.systemBackground))

  


// 表单底部按钮

VStack {

    // 表单内容

    ForEach(0..<3) {

        Text("表单项 \($0 + 1)")

            .padding()

            .background(Color.gray.opacity(0.1))

            .cornerRadius(8)

            .padding(.horizontal)

    }

    

    Spacer()

    

    // 底部按钮

    Button("提交") {

        print("提交")

    }

    .buttonStyle(.borderedProminent)

    .padding()

}

适用场景

  • 工具栏:将标题居中,按钮放在两侧

  • 表单:将提交按钮固定在底部

  • 卡片:将内容推到顶部,操作按钮放在底部

  • 导航栏:创建平衡的布局

性能考虑

  • Spacer 是轻量级视图,对性能影响很小

  • 合理使用 Spacer 可以减少不必要的几何计算

  • 避免在不需要的地方使用 Spacer,可能会导致意外的布局行为

4.6 布局修饰符

框架修饰符

frame 修饰符用于控制视图的大小和对齐方式。


// 设置固定大小

Text("固定大小")

    .frame(width: 200, height: 100)

    .background(Color.yellow)

  


// 设置最大和最小大小

Text("灵活大小")

    .frame(minWidth: 100, maxWidth: 300, minHeight: 50, maxHeight: 150)

    .background(Color.blue)

  


// 填充父容器

Text("填充")

    .frame(maxWidth: .infinity, maxHeight: .infinity)

    .background(Color.green)

  


// 带对齐的框架

Text("右对齐")

    .frame(width: 200, alignment: .trailing)

    .background(Color.gray.opacity(0.2))

位置修饰符

positionoffset 修饰符用于调整视图的位置。


// 绝对位置

Text("绝对位置")

    .position(x: 100, y: 100)

  


// 相对偏移

Text("相对偏移")

    .offset(x: 50, y: 20)

  


// 组合使用

ZStack {

    Text("基础位置")

        .background(Color.yellow)

    

    Text("偏移位置")

        .offset(x: 50, y: 30)

        .background(Color.red)

}

布局优先级

layoutPriority 修饰符用于设置视图的布局优先级。


HStack {

    Text("短文本")

        .layoutPriority(1// 高优先级

        .background(Color.yellow)

    

    Text("这是一段非常长的文本,会被截断")

        .background(Color.blue)

}

.frame(width: 200)

适用场景

  • 响应式设计:根据屏幕尺寸调整视图大小

  • 自定义布局:精确控制视图位置

  • 复杂界面:处理不同优先级的内容

  • 动态布局:根据内容自动调整

4.7 网格布局:LazyVGrid 和 LazyHGrid

网格布局介绍

LazyVGridLazyHGrid 是 SwiftUI 中用于创建网格布局的容器,它们支持延迟加载,适用于大量数据。网格布局使用 GridItem 来定义列或行的大小和间距。

基本用法


// 定义网格列

let columns = [

    GridItem(.flexible()),

    GridItem(.flexible()),

    GridItem(.flexible())

]

  


// 垂直网格

ScrollView {

    LazyVGrid(columns: columns, spacing: 10) {

        ForEach(1..<10) { index in

            Rectangle()

                .fill(Color(hue: Double(index)/10, saturation: 0.8, brightness: 0.8))

                .frame(height: 80)

                .overlay(

                    Text("\(index)")

                        .foregroundColor(.white)

                        .font(.headline)

                )

        }

    }

    .padding()

}

  


// 水平网格

let rows = [

    GridItem(.flexible()),

    GridItem(.flexible())

]

  


ScrollView(.horizontal) {

    LazyHGrid(rows: rows, spacing: 10) {

        ForEach(1..<10) { index in

            Rectangle()

                .fill(Color(hue: Double(index)/10, saturation: 0.8, brightness: 0.8))

                .frame(width: 100)

                .overlay(

                    Text("\(index)")

                        .foregroundColor(.white)

                        .font(.headline)

                )

        }

    }

    .padding()

}

GridItem 配置

GridItem 支持多种大小配置:

  • .fixed:固定大小

  • .flexible:灵活大小(默认)

  • .adaptive:自适应大小,尽可能多的列


// 固定大小的列

let fixedColumns = [

    GridItem(.fixed(100)),

    GridItem(.fixed(100)),

    GridItem(.fixed(100))

]

  


// 自适应列数

let adaptiveColumns = [

    GridItem(.adaptive(minimum: 80, maximum: 120))

]

  


// 混合配置

let mixedColumns = [

    GridItem(.fixed(80)),

    GridItem(.flexible()),

    GridItem(.fixed(80))

]

适用场景

  • 图片网格:相册、产品展示

  • 图标网格:应用图标、功能入口

  • 数据网格:表格数据展示

  • 响应式布局:自适应不同屏幕尺寸

4.8 列表和表单:List 和 Form

List 列表

List 是 SwiftUI 中用于显示滚动列表的容器,自动处理单元格布局和数据展示。


// 基本列表

List {

    Text("项目 1")

    Text("项目 2")

    Text("项目 3")

}

  


// 带分组的列表

List {

    Section(header: Text("分组 1")) {

        Text("项目 1")

        Text("项目 2")

    }

    

    Section(header: Text("分组 2")) {

        Text("项目 3")

        Text("项目 4")

    }

}

  


// 动态列表

let items = ["苹果", "香蕉", "橙子", "葡萄"]

  


List(items, id: \.self) { item in

    HStack {

        Image(systemName: "fruit")

        Text(item)

    }

}

Form 表单

Form 是专门用于表单布局的容器,提供了预设的样式和间距。


// 基本表单

Form {

    TextField("用户名", text: .constant(""))

    SecureField("密码", text: .constant(""))

    Toggle("记住密码", isOn: .constant(true))

    Button("登录") {}

}

  


// 带分组的表单

Form {

    Section(header: Text("个人信息")) {

        TextField("姓名", text: .constant(""))

        TextField("邮箱", text: .constant(""))

    }

    

    Section(header: Text("偏好设置")) {

        Toggle("接收通知", isOn: .constant(true))

        Picker("主题", selection: .constant("浅色")) {

            Text("浅色").tag("浅色")

            Text("深色").tag("深色")

        }

    }

    

    Section {

        Button("保存设置") {}

    }

}

适用场景

  • List:显示结构化数据列表、设置项、联系人

  • Form:创建用户输入表单、设置页面、注册登录页面

4.9 几何读取器:GeometryReader

GeometryReader 介绍

GeometryReader 是一个特殊的容器,它可以读取父视图的几何信息(尺寸和位置),并根据这些信息来布局子视图。


// 基本用法

GeometryReader { geometry in

    VStack {

        Text("宽度: \(geometry.size.width)")

        Text("高度: \(geometry.size.height)")

        Text("安全区域: \(geometry.safeAreaInsets.top)")

    }

    .frame(width: geometry.size.width, height: geometry.size.height)

    .background(Color.gray.opacity(0.1))

}

  


// 根据父视图大小调整子视图

GeometryReader { geometry in

    HStack(spacing: 0) {

        Color.red

            .frame(width: geometry.size.width * 0.3)

        Color.green

            .frame(width: geometry.size.width * 0.3)

        Color.blue

            .frame(width: geometry.size.width * 0.4)

    }

}

.frame(height: 100)

  


// 自适应网格

GeometryReader { geometry in

    let columns = Int(geometry.size.width / 100)

    let gridItems = Array(repeating: GridItem(.flexible()), count: max(columns, 1))

    

    LazyVGrid(columns: gridItems, spacing: 10) {

        ForEach(1..<10) { index in

            Rectangle()

                .fill(Color(hue: Double(index)/10, saturation: 0.8, brightness: 0.8))

                .frame(height: 80)

                .overlay(

                    Text("\(index)")

                        .foregroundColor(.white)

                )

        }

    }

    .padding()

}

适用场景

  • 响应式布局:根据屏幕尺寸调整布局

  • 自定义布局:需要精确控制尺寸的场景

  • 动画效果:基于几何信息创建动画

  • 复杂布局:需要基于父视图尺寸的布局

4.10 其他重要布局组件

Divider 分隔线

Divider 用于在视图之间创建水平或垂直的分隔线。


// 水平分隔线

VStack {

    Text("顶部")

    Divider()

    Text("底部")

}

  


// 垂直分隔线

HStack {

    Text("左侧")

    Divider()

    Text("右侧")

}

.frame(height: 50)

Group 视图分组

Group 用于将多个视图组合在一起,作为一个整体应用修饰符。


// 分组应用修饰符

Group {

    Text("项目 1")

    Text("项目 2")

    Text("项目 3")

}

.foregroundColor(.blue)

.font(.headline)

  


// 条件渲染

Group {

    if true {

        Text("显示这个")

    } else {

        Text("显示那个")

    }

}

自定义布局(iOS 16+)

iOS 16 引入了 Layout 协议,允许创建完全自定义的布局。


// 简单的自定义布局

struct SimpleLayout: Layout {

    func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {

        // 计算布局尺寸

        return CGSize(width: proposal.width ?? 300, height: proposal.height ?? 200)

    }

    

    func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {

        // 放置子视图

        for (index, subview) in subviews.enumerated() {

            let x = bounds.minX + CGFloat(index) * 50

            let y = bounds.midY

            subview.place(at: CGPoint(x: x, y: y), proposal: .unspecified)

        }

    }

}

  


// 使用自定义布局

SimpleLayout {

    Text("1")

    Text("2")

    Text("3")

    Text("4")

}

.frame(height: 100)

.background(Color.gray.opacity(0.1))

实战:创建一个登录页面

需求分析

创建一个包含以下元素的登录页面:

  1. 应用图标和标题

  2. 用户名输入框

  3. 密码输入框(带可见性切换)

  4. 登录按钮

  5. 忘记密码链接

  6. 注册链接

代码实现


import SwiftUI

  


struct LoginView: View {

    // 状态变量

    @State private var username = ""

    @State private var password = ""

    @State private var showPassword = false

    

    var body: some View {

        ZStack {

            // 背景

            LinearGradient(

                colors: [.blue.opacity(0.1), .purple.opacity(0.1)],

                startPoint: .top,

                endPoint: .bottom

            )

            .ignoresSafeArea()

            

            VStack(spacing: 24) {

                // 应用图标和标题

                VStack(spacing: 12) {

                    Image(systemName: "lock.fill")

                        .resizable()

                        .aspectRatio(contentMode: .fit)

                        .frame(width: 80, height: 80)

                        .foregroundStyle(.blue)

                    

                    Text("欢迎回来")

                        .font(.largeTitle)

                        .fontWeight(.bold)

                    

                    Text("请登录以继续")

                        .foregroundStyle(.secondary)

                }

                

                // 输入区域

                VStack(spacing: 16) {

                    // 用户名输入框

                    TextField(

                        "用户名",

                        text: $username,

                        prompt: Text("请输入用户名")

                    )

                    .textFieldStyle(.roundedBorder)

                    .padding(.horizontal)

                    

                    // 密码输入框

                    ZStack(alignment: .trailing) {

                        if showPassword {

                            TextField(

                                "密码",

                                text: $password,

                                prompt: Text("请输入密码")

                            )

                        } else {

                            SecureField(

                                "密码",

                                text: $password,

                                prompt: Text("请输入密码")

                            )

                        }

                        

                        Button(action: {

                            showPassword.toggle()

                        }) {

                            Image(systemName: showPassword ? "eye.slash.fill" : "eye.fill")

                                .foregroundStyle(.secondary)

                                .padding(.trailing, 16)

                        }

                    }

                    .textFieldStyle(.roundedBorder)

                    .padding(.horizontal)

                    

                    // 忘记密码

                    HStack {

                        Spacer()

                        Button("忘记密码?") {

                            print("忘记密码")

                        }

                        .foregroundStyle(.blue)

                        .padding(.trailing)

                    }

                }

                

                // 登录按钮

                Button("登录") {

                    print("登录")

                }

                .buttonStyle(.borderedProminent)

                .tint(.blue)

                .padding(.horizontal)

                .frame(maxWidth: .infinity)

                

                // 注册链接

                HStack {

                    Text("还没有账号?")

                    Button("立即注册") {

                        print("注册")

                    }

                    .foregroundStyle(.blue)

                }

                

                Spacer()

            }

            .padding(.top, 60)

        }

    }

}

  


#Preview {

    LoginView()

}

代码解析

  1. ZStack:用于层叠背景和内容,创建深度感

  2. VStack:用于垂直排列各个部分,保持页面结构清晰

  3. HStack:用于水平排列忘记密码链接和注册链接

  4. Spacer:用于底部填充空间,将内容推到顶部

  5. TextField 和 SecureField:用于用户输入

  6. Button:用于操作按钮

  7. LinearGradient:用于创建美观的背景渐变

  8. ** @State**:用于管理视图状态

实战:创建一个产品详情页

需求分析

创建一个产品详情页,包含以下元素:

  1. 产品图片

  2. 产品标题和价格

  3. 产品描述

  4. 规格选择

  5. 购买按钮

代码实现


import SwiftUI

  


struct ProductDetailView: View {

    // 状态变量

    @State private var selectedColor = "红色"

    @State private var selectedSize = "M"

    @State private var quantity = 1

    

    // 产品数据

    let productName = "SwiftUI 高级教程"

    let productPrice = "¥99.00"

    let productDescription = "本教程涵盖了 SwiftUI 的高级特性,包括动画、手势、布局和性能优化等内容。通过实际项目案例,帮助你掌握 SwiftUI 的核心概念和最佳实践。"

    let colors = ["红色", "蓝色", "黑色"]

    let sizes = ["S", "M", "L", "XL"]

    

    var body: some View {

        ScrollView {

            VStack(spacing: 20) {

                // 产品图片

                ZStack {

                    Color.gray.opacity(0.1)

                        .frame(height: 300)

                    

                    Image(systemName: "book.fill")

                        .resizable()

                        .aspectRatio(contentMode: .fit)

                        .frame(width: 150, height: 150)

                        .foregroundStyle(.blue)

                }

                

                // 产品信息

                VStack(alignment: .leading, spacing: 12) {

                    HStack {

                        Text(productName)

                            .font(.title)

                            .fontWeight(.bold)

                        Spacer()

                        Text(productPrice)

                            .font(.title)

                            .fontWeight(.bold)

                            .foregroundStyle(.red)

                    }

                    

                    // 产品描述

                    Text(productDescription)

                        .foregroundStyle(.secondary)

                        .lineLimit(nil)

                    

                    // 颜色选择

                    Text("颜色")

                        .font(.headline)

                    HStack(spacing: 10) {

                        ForEach(colors, id: \.self) {

                            color in

                            Button(action: {

                                selectedColor = color

                            }) {

                                Text(color)

                                    .padding(8)

                                    .background(selectedColor == color ? Color.blue : Color.gray.opacity(0.1))

                                    .foregroundStyle(selectedColor == color ? .white : .primary)

                                    .cornerRadius(4)

                            }

                        }

                    }

                    

                    // 尺寸选择

                    Text("尺寸")

                        .font(.headline)

                    HStack(spacing: 10) {

                        ForEach(sizes, id: \.self) {

                            size in

                            Button(action: {

                                selectedSize = size

                            }) {

                                Text(size)

                                    .padding(8)

                                    .background(selectedSize == size ? Color.blue : Color.gray.opacity(0.1))

                                    .foregroundStyle(selectedSize == size ? .white : .primary)

                                    .cornerRadius(4)

                            }

                        }

                    }

                    

                    // 数量选择

                    Text("数量")

                        .font(.headline)

                    HStack {

                        Button(action: {

                            if quantity > 1 {

                                quantity -= 1

                            }

                        }) {

                            Image(systemName: "minus.circle")

                                .font(.system(size: 24))

                        }

                        

                        Text("\(quantity)")

                            .font(.headline)

                            .padding(.horizontal, 20)

                        

                        Button(action: {

                            quantity += 1

                        }) {

                            Image(systemName: "plus.circle")

                                .font(.system(size: 24))

                        }

                    }

                }

                .padding()

                

                // 购买按钮

                Button("加入购物车") {

                    print("加入购物车")

                }

                .buttonStyle(.borderedProminent)

                .tint(.blue)

                .padding(.horizontal)

                .frame(maxWidth: .infinity)

                .padding(.bottom, 30)

            }

        }

        .navigationTitle("产品详情")

        .navigationBarTitleDisplayMode(.inline)

    }

}

  


#Preview {

    ProductDetailView()

}

代码解析

  1. ScrollView:用于滚动显示产品详情

  2. ZStack:用于显示产品图片和背景

  3. VStack:用于垂直排列产品信息

  4. HStack:用于水平排列价格、颜色选择、尺寸选择和数量控制

  5. Button:用于选择颜色、尺寸和调整数量

  6. ** @State**:用于管理用户选择的状态

小结

本章详细介绍了 SwiftUI 中的基础布局系统,包括:

  • VStack:垂直堆叠视图,适用于从上到下的布局

  • HStack:水平堆叠视图,适用于从左到右的布局

  • ZStack:层叠视图,适用于需要层级关系的布局

  • 间距与对齐:控制视图之间的空间和位置关系

  • Spacer:占据剩余空间,实现灵活布局

  • 布局修饰符:控制视图的大小、位置和优先级

  • 网格布局:LazyVGrid、LazyHGrid,用于创建网格

  • 列表和表单:List、Form,用于显示列表和表单

  • 几何读取器:GeometryReader,用于获取父视图尺寸

  • 其他布局组件:Divider、Group、自定义布局

  • 实战案例:登录页面和产品详情页的完整实现

布局最佳实践

  1. 保持简洁:使用最少的容器实现所需布局

  2. 嵌套合理:避免过深的布局嵌套

  3. 响应式设计:考虑不同屏幕尺寸的布局适配

  4. 性能优化:对于大量数据使用 Lazy 容器

  5. 一致性:保持间距和对齐的一致性

  6. 可访问性:确保布局对所有用户都友好

通过本章的学习,你已经掌握了 SwiftUI 中最基本的布局技巧,能够创建各种常见的布局结构。在实际开发中,你可以根据具体需求选择合适的布局容器和技术,创建美观、响应式的用户界面。

参考资料

本内容为《SwiftUI 基础教程》第四章,欢迎关注后续更新。