从一个 CodeBreaker 界面开始,认识 SwiftUI 的声明式结构、布局和状态表达。跟随讲义在 Xcode 中逐段修改与预览,理解代码如何变成屏幕上的画面。
阅读目录 · 14 节
- 1) Swift 与 SwiftUI 的一句话理解
- 2) Xcode 三大区域:左中右怎么用
- 3) SwiftUI 核心结构:App / Scene / View / struct / protocol
- 4) 布局容器:VStack / HStack / ZStack
- 5) modifier 修饰符:顺序为何会改变结果
- 6) CodeBreaker 页面拆解
- 7) 数据与珠子视图:let/var 与可扩展 Pegs
- 8) ForEach:循环与 id 的坑
- 9) MatchPegs:黑钉/白钉/空 + 深色模式
- 10) enum:让状态表达更清楚
- 11) 常见错误清单
- 12) 任务与挑战
- 13) 实现约束
- 这节课真正要带走的能力
学习目标。 理解 SwiftUI 的声明式与状态驱动模型
核心能力。 布局容器、修饰符顺序、组件封装、枚举建模
实践方式。 以 CodeBreaker UI 为主线,边讲边改边预览
适配要求。 iPhone 运行正常,Light / Dark Mode 都可读
项目 GitHub:https://github.com/Hean-Yi/CodeBreaker.git
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 实现。

关键理解:some View / some Scene 是不透明返回类型。你返回的是具体类型,但对外隐藏类型细节。
4) 布局容器:VStack / HStack / ZStack
2. 容器决定方向,修饰符决定观感
VStack:从上到下排。HStack:从左到右排。ZStack:前后叠放,后写的盖在前面。

5) modifier 修饰符:顺序为何会改变结果
3. 修饰符是“逐层包裹”,不是独立开关
同一组修饰符,顺序不同,最终渲染不同。最常见是 padding 与 background。

进阶组合也一样:clipShape、shadow、frame、onTapGesture 的先后会影响视觉与交互命中范围。

6) CodeBreaker 页面拆解
本次课堂先实现基础版 UI,可拆成两块:
- 一排猜测珠子(Pegs Row)。
- 一组反馈钉子(MatchPegs,2x2 布局)。
7) 数据与珠子视图:let/var 与可扩展 Pegs
4. 变量语义:优先 let,必要时再 var
不变数据优先 let,变化数据再用 var。这会直接减少状态错误和误改。

珠子行建议写成可扩展函数或组件,支持 3~6 个甚至更多:
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。

9) MatchPegs:黑钉/白钉/空 + 深色模式
exact:黑钉(颜色对、位置对)。inexact:白钉(颜色对、位置错)。noMatch:空钉(透明占位,保留布局)。
配色建议使用语义色(如 .primary),让 Light / Dark 自动适配,避免手写颜色在深色模式失真。
10) enum:让状态表达更清楚
6. 不要用魔法数字表达状态
用 enum 明确状态语义,switch 分发行为,可读性和可维护性都更高。

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语义下)。 - 项目里至少体现一次“修饰符顺序影响结果”的正确实践。
这节课真正要带走的能力
把讲义中的概念用到自己的项目里,在修改、运行与解释代码的过程中巩固理解。
