用途
SwiftUI UI Patterns 用于在创建或重构 SwiftUI 屏幕、流程或可复用 UI 组件时提供经过验证的界面模式指导,重点覆盖导航、弹窗(sheets)、异步状态、预览和组件模式。
何时使用
- 创建或重构 SwiftUI 屏幕、流程或可复用 UI 组件时。
- 需要关于导航、sheets、异步状态、预览或组件模式的指导时。
使用方式
根据目标选择路径:
已有项目
- 确定功能或屏幕及其主要交互模型(列表、详情、编辑器、设置、标签页)。
- 在仓库中用
rg "TabView\("或类似方式查找相近示例,然后阅读最接近的 SwiftUI 视图。 - 应用本地约定:优先使用 SwiftUI 原生状态,尽量保持状态局部化,共享依赖使用环境注入。
- 从
references/components-index.md中选择相关组件参考并遵循其指导。 - 如果交互通过拖动或滚动主内容来揭示次要内容,在手动实现手势前先阅读
references/scroll-reveal.md。 - 使用小而专注的子视图和 SwiftUI 原生数据流构建视图。
新项目脚手架
- 从
references/app-wiring.md开始接线 TabView + NavigationStack + sheets。 - 基于提供的骨架添加最小的 AppTab 和 RouterPath。
- 根据首先需要的 UI 选择下一个组件参考(TabView、NavigationStack、Sheets)。
- 随着新屏幕的加入扩展路由和 sheet 枚举。
通用规则
- 使用现代 SwiftUI 状态(@State、@Binding、@Observable、@Environment),避免不必要的视图模型。
- 如果部署目标包含 iOS 16 或更早版本,无法使用 iOS 17 引入的 Observation API,则回退到 ObservableObject:根所有权用 @StateObject,注入观察用 @ObservedObject,@EnvironmentObject 仅用于真正共享的应用级状态。
- 优先组合;保持视图小而专注。
- 使用 async/await 配合 .task 和显式的加载/错误状态。关于重启、取消和防抖指导,阅读
references/async-state.md。 - 将共享应用服务放在 @Environment 中,但功能局部依赖和模型优先使用显式初始化器注入。根接线模式阅读
references/app-wiring.md。 - 优先使用适合部署目标的最新 SwiftUI API,并在模式依赖最低 OS 版本时明确指出。
- 仅在编辑遗留文件时保留现有遗留模式。
- 遵循项目的格式化和风格指南。
- Sheets:当状态表示选中的模型时,优先使用
.sheet(item:)而非.sheet(isPresented:)。避免在 sheet body 内使用 if let。Sheets 应自己拥有动作并在内部调用 dismiss(),而不是转发 onCancel/onConfirm 闭包。 - 滚动驱动揭示:优先从滚动偏移推导归一化进度值,并由该单一事实来源驱动视觉状态。除非仅靠滚动无法表达交互,否则避免并行手势状态机。
状态所有权
使用与所有权模型匹配的最窄状态工具:
| 场景 | 首选模式 |
|---|---|
| 单个视图拥有的本地 UI 状态 | @State |
| 子视图修改父级拥有的值状态 | @Binding |
| iOS 17+ 上根拥有的引用模型 | @State 配合 @Observable 类型 |
| iOS 17+ 上子视图读取或修改注入的 @Observable 模型 | 作为存储属性显式传入 |
| 共享应用服务或配置 | @Environment(Type.self) |
| iOS 16 及更早的遗留引用模型 | 根处 @StateObject,注入时 @ObservedObject |
先选择所有权位置,再选择包装器。当普通值状态足够时,不要引入引用模型。
跨领域参考
references/navigationstack.md:导航所有权、每标签页历史、枚举路由。references/sheets.md:集中式模态呈现和枚举驱动的 sheets。references/deeplinks.md:URL 处理及将外部链接路由到应用目的地。references/app-wiring.md:根依赖图、环境使用和应用外壳接线。references/async-state.md:.task、.task(id:)、取消、防抖和异步 UI 状态。references/previews.md:#Preview、fixtures、mock 环境和隔离预览设置。references/performance.md:稳定标识、观察范围、惰性容器和渲染成本护栏。
反模式
- 巨型视图,在一个文件中混合布局、业务逻辑、网络、路由和格式化。
- 为互斥的 sheets、alerts 或导航目的地使用多个布尔标志。
- 直接在 body 驱动的代码路径中进行实时服务调用,而不是在视图生命周期钩子或注入的模型/服务中。
- 使用 AnyView 绕过本应通过更好组合解决的类型不匹配。
- 在没有明确所有权理由的情况下,将每个共享依赖默认为 @EnvironmentObject 或全局路由器。
新 SwiftUI 视图的工作流程
- 在编写 UI 代码前,定义视图的状态、所有权位置和最低 OS 假设。
- 确定哪些依赖属于 @Environment,哪些应保持为显式初始化器输入。
- 勾勒视图层级、路由模型和呈现点;将重复部分提取为子视图。复杂导航阅读
references/navigationstack.md、references/sheets.md或references/deeplinks.md。在继续前构建并验证无编译器错误。 - 使用 .task 或 .task(id:) 实现异步加载,并在需要时提供显式加载和错误状态。当工作依赖变化的输入或取消时,阅读
references/async-state.md。 - 为主要和次要状态添加预览,然后在 UI 可交互时添加无障碍标签或标识符。当视图需要 fixtures 或注入 mock 依赖时,阅读
references/previews.md。 - 通过构建验证:确认无编译器错误,检查预览渲染不崩溃,确保状态变化正确传播,并合理检查列表标识和观察范围不会导致可避免的重新渲染。如果屏幕较大、滚动密集或频繁更新,阅读
references/performance.md。对于常见 SwiftUI 编译错误——缺少 @State 注解、模糊的 ViewBuilder 闭包或泛型类型不匹配——在更新调用点前解决它们。如果构建失败:仔细阅读错误消息,修复已识别的问题,然后重新构建再继续下一步。如果预览崩溃,隔离有问题的子视图,确认其状态初始化有效,然后重新运行预览再继续。
组件参考
使用 references/components-index.md 作为入口点。每个组件参考应包含:
- 意图和最佳适用场景。
- 使用本地约定的最小用法模式。
- 陷阱和性能注意事项。
- 当前仓库中现有示例的路径。
添加新组件参考
- 创建
references/<component>.md。 - 保持简短且可操作;链接到当前仓库中的具体文件。
- 用新条目更新
references/components-index.md。
限制
- 仅当任务明确匹配上述范围时使用此技能。
- 不要将输出视为环境特定验证、测试或专家审查的替代品。
- 如果缺少必需输入、权限、安全边界或成功标准,停止并请求澄清。