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

SwiftUI 導覽狀態探究

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.
Avatar for Ethan Huang Ethan Huang
October 23, 2021

SwiftUI 導覽狀態探究

MOPCON 2021

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

Avatar for Ethan Huang

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