Upgrade to Pro — share decks privately, control downloads, hide ads and more …

SwiftUI 導覽狀態探究

SwiftUI 導覽狀態探究

MOPCON 2021

SwiftUI 是用 state 來管理 view。只要 state 改變了, view 就跟著改變。但是傳統 iOS app 操作常見的畫面切換,如 navigation push 與 presentation,原生 SwiftUI 的作法比較陽春,或者可以說是沿用了 UIViewController 的結構。本題想探究 SwiftUI 能否比較簡便的 state 來統一管理 view 的 navigation 與 presentation。

Ethan Huang

October 23, 2021
Tweet

More Decks by Ethan Huang

Other Decks in Programming

Transcript

  1. ⾃我介紹 13 • iOS Developer since iOS 6 • weak

    self podcast 共同主持⼈ https://weakself.dev • ⟪13 的 Apple 開發者週報⟫主編 https://ethanhuang13.substack.com • Twitter https://twitter.com/ethanhuang13 • GitHub https://github.com/ethanhuang13
  2. SwiftUI 導覽狀態探究 Agenda • SwiftUI 的 state—view 關係 • iOS

    Navigation & Presentation • SwiftUI Navigation (Version 1~7) • Advanced Navigation/Presentation • Next step(s)?
  3. SwiftUI 的 state—view 關係 • State 與 view 綁定 •

    改變 state 就改變 view • 改變 view 就改變 state
  4. SwiftUI Navigation ⼀個簡單的筆記 app • 3 個畫⾯ • ListView →

    EditorView → DisplayView • 程式碼網址 
 https://github.com/ethanhuang13/SwiftUI-Navigation-Study
  5. Version 1 依照原⽣ SwiftUI 做 navigation 基本款 • 重點 •

    ForEach 包 NavigationLink。當 item 被刪除時會⾃動 pop • 缺點與限制 • 為了返回上⼀層,要寫 @Environment(\.presentationMode) • DisplayView 不能 pop 回到 ListView
  6. Version 2 寫個 `class Navigation: ObservableObject` 把 push 的狀態放進去 •

    重點 • 現在可以⽤⼀個物件集中管理 navigation 狀態 • 缺點與限制 • 可以⽤是可以⽤,但⼀定得寫 ObservableObject 嗎?
  7. Version 3 把 `class Navigation` 改成 value type • 重點

    • 其實也可以⼀開始就這麼寫,只是 SwiftUI 的教學往往告訴我們要處理較複 雜的 model 需要⽤ `ObservableObject` 或 class。然⽽ value type 完全可 以勝任 • 缺點與限制 • 每個畫⾯得⼀直往下傳遞 `Navigation`,能否更簡單
  8. Version 4 Custom Environment • 重點 • 學習了原⽣ SwiftUI 的

    presentationMode • 因為是 value type 所以⽤ Environment • 避開 reference type ⽤的 EnvironmentObject • 缺點與限制 • 每個畫⾯要 push 到另⼀個畫⾯,還是得專⾨寫個 NavigationLink, 
 有沒有辦法⾃由 push(類似 `UINavigationController`)呢?
  9. Version 5 Refactor `Navigation` and `ListView` • 前置作業 • 我們想多放⼀個按鈕,能直接

    push 到 DisplayView • 把 List 改成 ScrollView + LazyVStack • 缺點與限制 • 每個畫⾯要 push 到另⼀個畫⾯,還是得專⾨寫個 NavigationLink, 
 有沒有辦法⾃由 push(類似 `UINavigationController`)呢?
  10. Version 6 How about push freely? • 重點 • navigation

    各畫⾯其實是個 stack,能否⽤⼀個 Array 來表⽰、管理? • [Screen] • 加個 ContainerView 來包現在的畫⾯ • ListView 中的 notes 與 navigation 搬到 ContainerView
  11. Version 6 How about push freely? • 重點 • screens

    可以放在單⼀ state 管理,可以⾃由地切到任意⾴⾯了 • 缺點與限制 • 你給我等⼀下,沒有寫 NavigationLink 等於根本沒有做 push / pop 啊?
  12. Version 7 Introducing FlowStacks • 參考資料:FlowStacks 
 https://github.com/johnpatrickmorgan/FlowStacks • ⽬標:

    • 從 Screen 建立出⼀個 View • 這個 View 要有「下⼀個畫⾯的 NavigationLink」 • 再把這疊 [Screen] 對應的 Views 組成整個 app
  13. Version 7 Introducing FlowStacks • 重點: • 從 Screen 建立出⼀個

    View • 這個 View 要有「下⼀個畫⾯的 NavigationLink」 • 再把這疊 [Screen] 對應的 Views 組成整個 app • ⽤到了 Swift indirect enum, reduce 等功能 • 缺點與限制:⾒下⼀章
  14. 進階 Navigation 需求 直接切到某個狀態 • ❌跳過 push/pop 動畫(UIKit ⽀援,但 SwiftUI

    沒有提供此 API) • ❌⼀次 push 多層畫⾯(UIKit ⽀援,但 SwiftUI 呼叫 UIKit 的實作沒有⽀援) • Deep linking • State restoration • 如果可以做到的話,理論上可以隨時保留整個 app 當下的 UI 樣貌
  15. 進階需求 • Navigation 有的,Presentation 也要有 • ❌Presentation 在 UIKit 本⾝就不⽀援⼀次

    dismiss 多層 • 比如 dismiss 某畫⾯之後要跳出 alert • Navigation stacks 與 presentation stacks 混搭
  16. 更多研究 • FlowStacks 
 https://github.com/johnpatrickmorgan/FlowStacks • Point・Free TCA Navigation Study

    (Subscriber-Only) 
 https://twitter.com/pointfreeco/status/1445069787462262797?s=21
  17. 總結 • 過程勝於結果 • SwiftUI ⽬前在 Navigation/Presentation 還不能做到完美的 state—view 關係

    • Version 4 的 Environment(\.navigation) 已經符合⼀般需求 • 更進階的玩法還有待研究 • 程式碼網址 
 https://github.com/ethanhuang13/SwiftUI-Navigation-Study