学习目标
理解 SwiftUI 的声明式与状态驱动模型
核心能力
布局容器、修饰符顺序、组件封装、枚举建模
实践方式
以 CodeBreaker UI 为主线,边讲边改边预览
适配要求
iPhone 运行正常,Light / Dark Mode 都可读
阅读建议: 按章节顺序走一遍,并在 Xcode 同步跟敲。每一节里都给了最小可运行写法。
项目 GitHub:https://github.com/Hean-Yi/CodeBreaker.git
项目 GitHub:https://github.com/Hean-Yi/CodeBreaker.git
目录
- Swift 与 SwiftUI 的一句话理解
- Xcode 三大区域:左中右怎么用
- SwiftUI 核心结构:App / Scene / View / struct / protocol
- 布局容器:VStack / HStack / ZStack
- modifier 修饰符:顺序为何会改变结果
- CodeBreaker 页面拆解
- 数据与珠子视图:let/var 与可扩展 Pegs
- ForEach:循环与 id 的坑
- MatchPegs:黑钉/白钉/空 + 深色模式
- enum:让状态表达更清楚
- 常见错误清单
- 任务与挑战
- 实现约束
1) Swift 与 SwiftUI 的一句话理解
Swift 是现代多范式语言,支持面向对象、面向协议和函数式特性。
SwiftUI 是声明式、状态驱动的 UI 框架。你描述“当前状态下界面应该是什么样”,状态变了,界面自动同步刷新。
直观对比:UIKit 更像手工搬砖,SwiftUI 更像配置目标效果。
2) Xcode 三大区域:左中右怎么用
- 左侧 Project Navigator: 文件与资源管理,如 `Assets.xcassets` 与 Swift 文件。
- 中间 Editor: 代码编辑与报错定位。
- 右侧 Canvas Preview: 实时预览 UI,学习阶段建议常开。
3) SwiftUI 核心结构:App / Scene / View / struct / protocol
1
从入口到视图:先理解“层级关系”
`@main` 声明应用入口,`App` 提供 `Scene`,`Scene` 承载页面,页面由 `View` 组成,通常以 `struct` 实现。
图 1:App / Scene / View / Struct 的层级和职责。关键理解:`some View` / `some Scene` 是不透明返回类型。你返回的是具体类型,但对外隐藏类型细节。
4) 布局容器:VStack / HStack / ZStack
2
容器决定方向,修饰符决定观感
- `VStack`:从上到下排。
- `HStack`:从左到右排。
- `ZStack`:前后叠放,后写的盖在前面。
图 2:容器三兄弟对应三种排布模型。5) modifier 修饰符:顺序为何会改变结果
3
修饰符是“逐层包裹”,不是独立开关
同一组修饰符,顺序不同,最终渲染不同。最常见是 `padding` 与 `background`。
图 3:`padding` 与 `background` 顺序变化会改变背景覆盖范围。进阶组合也一样:`clipShape`、`shadow`、`frame`、`onTapGesture` 的先后会影响视觉与交互命中范围。
图 4:修饰器链路会影响阴影是否可见、点击区域是否正确。6) CodeBreaker 页面拆解
本次课堂先实现基础版 UI,可拆成两块:
- 一排猜测珠子(Pegs Row)。
- 一组反馈钉子(MatchPegs,2x2 布局)。
7) 数据与珠子视图:let/var 与可扩展 Pegs
4
变量语义:优先 let,必要时再 var
不变数据优先 `let`,变化数据再用 `var`。这会直接减少状态错误和误改。
图 5:常量与变量职责分离,有助于代码稳定性。珠子行建议写成可扩展函数或组件,支持 3~6 个甚至更多:
swift
func pegsView(colors: [Color]) -> some View {
HStack {
ForEach(colors.indices, id: \.self) { index in
RoundedRectangle(cornerRadius: 10)
.foregroundStyle(colors[index])
.aspectRatio(1, contentMode: .fit)
}
}
}8) ForEach:循环与 id 的坑
5
重复元素不要直接用 `id: \.self`
当数组内元素可能重复(例如两个相同颜色),`id: \.self` 可能导致身份冲突。更稳妥的是用下标或 `Identifiable`。
图 6:ForEach 的核心不是“循环”,而是“稳定身份识别”。9) MatchPegs:黑钉/白钉/空 + 深色模式
- `exact`:黑钉(颜色对、位置对)。
- `inexact`:白钉(颜色对、位置错)。
- `noMatch`:空钉(透明占位,保留布局)。
配色建议使用语义色(如 `.primary`),让 Light / Dark 自动适配,避免手写颜色在深色模式失真。
10) enum:让状态表达更清楚
6
不要用魔法数字表达状态
用 `enum` 明确状态语义,`switch` 分发行为,可读性和可维护性都更高。
图 7:枚举能把“看不懂的数字状态”升级为“可读的业务状态”。swift
enum Match {
case exact
case inexact
case noMatch
}11) 常见错误清单
- 返回视图的函数请写 `-> some View`,不要写 `-> View`。
- 统计计数通常用 `filter { ... }.count`。
- ForEach 的 `id` 要稳定,不要盲目 `\.self`。
- 深色模式尽量使用语义色(`.primary`、`.secondary`)。
12) 任务与挑战
任务 1-3(基础必做)
- 完成 CodeBreaker UI 原型:Pegs + MatchMarkers。
- 做原生场景 Preview:dummy pegs + MatchMarkers 组合预览。
- 让 MatchMarkers 支持 3~6 个结果,不写死 4 个。
任务 4-6(验证完整性)
- Preview 覆盖 3/4/5/6 以及混合状态组合。
- dummy pegs 数量需与 matches 数量一致。
- Light / Dark 都要验证可读性与边界表现。
挑战 1-2(组件化)
- `PegsRow` 与 `MatchMarkers` 组件化,外部只传数据。
- peg 数量参数化(3~6),Preview 里做参数扫描。
挑战 3-4(工程化 + 视觉)
- 做异常输入保护(截断/断言/可读 debug 信息)。
- 尝试 Material 拟态玻璃效果并保持深浅色可读。
13) 实现约束
- 状态表达:`enum Match { case exact, inexact, noMatch }`。
- ForEach:提供稳定 id(下标或 `Identifiable`)。
- 允许在 View 里用 `if` 分支处理显示逻辑(`@ViewBuilder` 语义下)。
- 项目里至少体现一次“修饰符顺序影响结果”的正确实践。
