SKILL.md
readonlyread-only
name
swiftui-ui-patterns
description
建構 SwiftUI 檢視與元件的實務指南與範例驅動指引,涵蓋導覽層級、自訂檢視修飾器,以及使用堆疊與格線的響應式佈局。適用於建立或重構 SwiftUI UI、使用 TabView 設計分頁架構、以 VStack/HStack 組合畫面、管理 @State 或 @Binding、建構宣告式 iOS 介面,或需要特定元件的模式與範例時。
SwiftUI UI 模式
快速入門
根據你的目標選擇學習路徑:
既有專案
- 識別功能或畫面及其主要互動模式(列表、詳細、編輯、設定、分頁)。
- 在 repo 中以
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 主體中使用if let。Sheet 應擁有自己的動作,並在內部呼叫dismiss(),而不是轉發onCancel/onConfirm閉包。 - 滾動驅動的揭示:偏好從滾動偏移推導出標準化的進度值,並從該單一事實來源驅動視覺狀態。除非僅靠滾動無法表達互動,否則避免使用並行手勢狀態機。
狀態擁有權摘要
使用最窄的狀態工具來匹配擁有權模型:
| 情境 | 偏好模式 |
|---|---|
| 由單一檢視擁有的本機 UI 狀態 | @State |
| 子檢視修改父檢視擁有的值類型狀態 | @Binding |
| iOS 17+ 上由根擁有的參考模型 | @State 搭配 @Observable 類型 |
子檢視讀取或修改注入的 @Observable 模型(iOS 17+) |
明確傳遞為儲存屬性 |
| 共享的應用服務或設定 | @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、測試資料、模擬環境、隔離預覽設定。references/performance.md:穩定識別、觀察範圍、惰性容器、渲染成本防護。
反模式
- 巨型檢視:在單一檔案中混合佈局、商業邏輯、網路請求、路由和格式化。
- 使用多個布林旗標來表示互斥的 sheets、警示或導覽目的地。
- 直接在
body驅動的程式碼路徑中呼叫即時服務,而非使用檢視生命週期鉤子或注入的模型/服務。 - 使用
AnyView來繞過應透過更好組合解決的類型不匹配。 - 在沒有明確擁有權理由的情況下,將每個共享依賴預設為
@EnvironmentObject或全域路由器。
新 SwiftUI 檢視的工作流程
- 在撰寫 UI 程式碼之前,先定義檢視的狀態、擁有權位置和最低 OS 假設。
- 識別哪些依賴屬於
@Environment,哪些應保留為明確的初始化器輸入。 - 草擬檢視層級、路由模型和呈現點;將重複部分提取為子檢視。對於複雜導覽,請閱讀
references/navigationstack.md、references/sheets.md或references/deeplinks.md。在繼續之前,建置並確認無編譯錯誤。 - 使用
.task或.task(id:)實作非同步載入,並在需要時加入明確的載入和錯誤狀態。當工作依賴於變化的輸入或取消時,請閱讀references/async-state.md。 - 為主狀態和次要狀態加入預覽,然後在 UI 可互動時加入無障礙標籤或識別碼。當檢視需要測試資料或注入的模擬依賴時,請閱讀
references/previews.md。 - 透過建置驗證:確認無編譯錯誤,檢查預覽是否正常渲染而不崩潰,確保狀態變更正確傳播,並檢查列表識別和觀察範圍不會導致可避免的重複渲染。如果畫面很大、滾動頻繁或經常更新,請閱讀
references/performance.md。對於常見的 SwiftUI 編譯錯誤(缺少@State註解、模糊的ViewBuilder閉包、或泛型類型不匹配),請在更新呼叫點之前解決。**如果建置失敗:**仔細閱讀錯誤訊息,修正識別的問題,然後重新建置再繼續下一步。如果預覽崩潰,請隔離有問題的子檢視,確認其狀態初始化有效,然後重新執行預覽再繼續。
元件參考
使用 references/components-index.md 作為入口點。每個元件參考應包含:
- 意圖與最佳適用情境。
- 符合本地慣例的最小使用模式。
- 陷阱與效能注意事項。
- 目前 repo 中現有範例的路徑。
新增元件參考
- 建立
references/<component>.md。 - 保持簡短且可操作;連結到目前 repo 中的具體檔案。
- 使用新條目更新
references/components-index.md。






