ScenePhase 可以用來監聽視窗正被操作的狀態。
SwiftUI ScenePhase 概覽
在使用者操作 App 的過程中,可能會使用到一半就滑掉,去使用別的 App,然後一下子又回來。在這樣的情境下,系統會將 App 的 Scene 在不同的階段之間做切換,而我們就能在這樣的生命週期轉變時,去做對應的事。
讀取 ScenePhase
在 SwiftUI 中,要讀取 ScenePhase 非常簡單!可以直接用 @Environment 拿到環境變數:
@Environment(\.scenePhase) private var scenePhase
注意
不過 scenePhase 這個環境變數的意義,會因為我們取值的地方不同而有不同,主要可以分成以下三種:在 View 裡、在 App 裡、在 Scene 裡。
在 View 裡讀取 ScenePhase
如果我們在某個 View 裡讀取 scenePhase 時,拿到的會是有著這個 View 的 Scene 的狀態。例如:我們可以在一個 View 不在前景時就停止計時器,而回到前景後再繼續計時:
struct Example: View {
@ObservedObject var model: DataModel
@Environment(\.scenePhase) private var scenePhase
var body: some View {
TimerView()
.onChange(of: scenePhase) { phase in
model.isTimerRunning = (phase == .active)
}
}
}
在 App 裡讀取 ScenePhase
如果我們直接在 App 下讀取 scenePhase 的話,就會拿到整個 App 的狀態。只要有 App 的任何一個 Scene 處在前景的話,scenePhase 就會是 active,而沒有任何一個 Scene 在前景時,scenePhase 就會是 inactive。
SwiftUI ScenePhase.background
background 是 ScenePhase 除了 active 與 inactive 以外的第三個狀態,這是個特別的狀態,代表著 App 再過不久就會被結束掉,而進到這個狀態也是給我們最後的機會去清掉我們該清的資源。
@main
struct Example: App {
@Environment(\.scenePhase) private var scenePhase
var body: some Scene {
WindowGroup {
MyRootView()
}
.onChange(of: scenePhase) { phase in
if phase == .background {
// 當 App 的所有 Scene 都進到 background 時
// 可以執行必要的資源清理
}
}
}
}
在 Scene 裡讀取 ScenePhase
當我們在客製的 Scene 裡讀取 scenePhase 時,會拿到組成這個 Scene 的所有 Scene 的狀態,有 Scene 在前景的話,就是 active,都不在前景的話,就是 inactive。
struct Example: Scene {
@Environment(\.scenePhase) private var scenePhase
var body: some Scene {
WindowGroup {
MyRootView()
}
WindowGroup {
AnotherView()
}
.onChange(of: scenePhase) { phase in
if phase == .background {
// 當所有 Scene 都進到 background 時
// 可以執行必要的資源清理
}
}
}
}
關於 XcodeProject
XcodeProject 創立於 2023,致力於協助開發者探索 Apple 的創新世界,學習在 iOS、iPadOS、macOS、tvOS、visionOS 與 watchOS 上開發 App,發現眾多技術與框架,讓開發者獲得更多能力。