swiftui-ui-patterns

swiftui-ui-patterns

熱門

建構 SwiftUI 檢視與元件的實務指南與範例驅動指引,涵蓋導覽層級、自訂檢視修飾器,以及使用堆疊與格線的響應式佈局。適用於建立或重構 SwiftUI UI、使用 TabView 設計分頁架構、以 VStack/HStack 組合畫面、管理 @State 或 @Binding、建構宣告式 iOS 介面,或需要特定元件的模式與範例時。

3854星標
203分支
更新於 2026/3/29
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。
  • 根據提供的骨架,加入最小化的 AppTabRouterPath
  • 根據你最先需要的 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 檢視的工作流程

  1. 在撰寫 UI 程式碼之前,先定義檢視的狀態、擁有權位置和最低 OS 假設。
  2. 識別哪些依賴屬於 @Environment,哪些應保留為明確的初始化器輸入。
  3. 草擬檢視層級、路由模型和呈現點;將重複部分提取為子檢視。對於複雜導覽,請閱讀 references/navigationstack.mdreferences/sheets.mdreferences/deeplinks.md在繼續之前,建置並確認無編譯錯誤。
  4. 使用 .task.task(id:) 實作非同步載入,並在需要時加入明確的載入和錯誤狀態。當工作依賴於變化的輸入或取消時,請閱讀 references/async-state.md
  5. 為主狀態和次要狀態加入預覽,然後在 UI 可互動時加入無障礙標籤或識別碼。當檢視需要測試資料或注入的模擬依賴時,請閱讀 references/previews.md
  6. 透過建置驗證:確認無編譯錯誤,檢查預覽是否正常渲染而不崩潰,確保狀態變更正確傳播,並檢查列表識別和觀察範圍不會導致可避免的重複渲染。如果畫面很大、滾動頻繁或經常更新,請閱讀 references/performance.md。對於常見的 SwiftUI 編譯錯誤(缺少 @State 註解、模糊的 ViewBuilder 閉包、或泛型類型不匹配),請在更新呼叫點之前解決。**如果建置失敗:**仔細閱讀錯誤訊息,修正識別的問題,然後重新建置再繼續下一步。如果預覽崩潰,請隔離有問題的子檢視,確認其狀態初始化有效,然後重新執行預覽再繼續。

元件參考

使用 references/components-index.md 作為入口點。每個元件參考應包含:

  • 意圖與最佳適用情境。
  • 符合本地慣例的最小使用模式。
  • 陷阱與效能注意事項。
  • 目前 repo 中現有範例的路徑。

新增元件參考

  • 建立 references/<component>.md
  • 保持簡短且可操作;連結到目前 repo 中的具體檔案。
  • 使用新條目更新 references/components-index.md