guide-swiftui-ui-patterns
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseGuide Skill — This is an expert workflow/pattern guide, not API reference documentation. Originally from Dimillian/Skills by Thomas Ricouard. MIT License.
指南技能 — 这是一份专业工作流/模式指南,而非API参考文档。 最初由Thomas Ricouard发布于Dimillian/Skills,采用MIT许可证。
SwiftUI UI Patterns
SwiftUI UI模式
Quick start
快速开始
Choose a track based on your goal:
根据你的目标选择对应的路径:
Existing project
现有项目
- Identify the feature or screen and the primary interaction model (list, detail, editor, settings, tabbed).
- Find a nearby example in the repo with or similar, then read the closest SwiftUI view.
rg "TabView\(" - Apply local conventions: prefer SwiftUI-native state, keep state local when possible, and use environment injection for shared dependencies.
- Choose the relevant component reference from and follow its guidance.
references/components-index.md - Build the view with small, focused subviews and SwiftUI-native data flow.
- 确定功能或页面,以及核心交互模式(列表、详情、编辑器、设置、标签页)。
- 使用或类似命令在仓库中查找相关示例,然后阅读最匹配的SwiftUI视图代码。
rg "TabView\(" - 遵循本地约定:优先使用SwiftUI原生状态,尽可能保持状态局部化,对共享依赖使用环境注入。
- 从中选择相关的组件参考并遵循其指引。
references/components-index.md - 使用小型、职责单一的子视图和SwiftUI原生数据流构建视图。
New project scaffolding
新项目脚手架
- Start with to wire TabView + NavigationStack + sheets.
references/app-scaffolding-wiring.md - Add a minimal and
AppTabbased on the provided skeletons.RouterPath - Choose the next component reference based on the UI you need first (TabView, NavigationStack, Sheets).
- Expand the route and sheet enums as new screens are added.
- 从开始,搭建TabView + NavigationStack + 弹窗的基础结构。
references/app-scaffolding-wiring.md - 基于提供的骨架代码添加最简的和
AppTab。RouterPath - 根据你首先需要的UI(TabView、NavigationStack、Sheets)选择对应的组件参考。
- 随着新页面的添加,扩展路由和弹窗枚举。
General rules to follow
需要遵循的通用规则
- Use modern SwiftUI state (,
@State,@Binding,@Observable) and avoid unnecessary view models.@Environment - Prefer composition; keep views small and focused.
- Use async/await with and explicit loading/error states.
.task - Maintain existing legacy patterns only when editing legacy files.
- Follow the project's formatter and style guide.
- Sheets: Prefer over
.sheet(item:)when state represents a selected model. Avoid.sheet(isPresented:)inside a sheet body. Sheets should own their actions and callif letinternally instead of forwardingdismiss()/onCancelclosures.onConfirm
- 使用现代SwiftUI状态(、
@State、@Binding、@Observable),避免不必要的视图模型。@Environment - 优先使用组合模式;保持视图小型且职责单一。
- 将async/await与结合使用,并明确设置加载/错误状态。
.task - 仅在编辑遗留文件时保留现有遗留模式。
- 遵循项目的格式化工具和风格指南。
- 弹窗(Sheets):当状态对应选中的模型时,优先使用而非
.sheet(item:)。避免在弹窗主体内部使用.sheet(isPresented:)。弹窗应自行管理其操作,内部调用if let,而非传递dismiss()/onCancel闭包。onConfirm
Workflow for a new SwiftUI view
新建SwiftUI视图的工作流
- Define the view's state and its ownership location.
- Identify dependencies to inject via .
@Environment - Sketch the view hierarchy and extract repeated parts into subviews.
- Implement async loading with and explicit state enum if needed.
.task - Add accessibility labels or identifiers when the UI is interactive.
- Validate with a build and update usage callsites if needed.
- 定义视图的状态及其归属位置。
- 确定需要通过注入的依赖。
@Environment - 梳理视图层级,将重复部分提取为子视图。
- 如有需要,使用实现异步加载和明确的状态枚举。
.task - 当UI具备交互性时,添加无障碍标签或标识符。
- 构建验证,如有需要更新调用处代码。
Component references
组件参考
Use as the entry point. Each component reference should include:
references/components-index.md- Intent and best-fit scenarios.
- Minimal usage pattern with local conventions.
- Pitfalls and performance notes.
- Paths to existing examples in the current repo.
以作为入口。每个组件参考应包含:
references/components-index.md- 用途和最佳适用场景。
- 符合本地约定的最简使用模式。
- 常见陷阱和性能注意事项。
- 指向当前仓库中现有示例的路径。
Sheet patterns
弹窗模式
Item-driven sheet (preferred)
数据驱动弹窗(推荐)
swift
@State private var selectedItem: Item?
.sheet(item: $selectedItem) { item in
EditItemSheet(item: item)
}swift
@State private var selectedItem: Item?
.sheet(item: $selectedItem) { item in
EditItemSheet(item: item)
}Sheet owns its actions
弹窗自行管理操作
swift
struct EditItemSheet: View {
@Environment(\.dismiss) private var dismiss
@Environment(Store.self) private var store
let item: Item
@State private var isSaving = false
var body: some View {
VStack {
Button(isSaving ? "Saving…" : "Save") {
Task { await save() }
}
}
}
private func save() async {
isSaving = true
await store.save(item)
dismiss()
}
}swift
struct EditItemSheet: View {
@Environment(\.dismiss) private var dismiss
@Environment(Store.self) private var store
let item: Item
@State private var isSaving = false
var body: some View {
VStack {
Button(isSaving ? "Saving…" : "Save") {
Task { await save() }
}
}
}
private func save() async {
isSaving = true
await store.save(item)
dismiss()
}
}Adding a new component reference
添加新的组件参考
- Create .
references/<component>.md - Keep it short and actionable; link to concrete files in the current repo.
- Update with the new entry.
references/components-index.md
- 创建文件。
references/<component>.md - 保持内容简短可落地;链接到当前仓库中的具体文件。
- 更新,添加新条目。
references/components-index.md