[英]How to animate transition between views in SwiftUI?
我有以下看法。
import SwiftUI
struct AppView: View {
@EnvironmentObject var appStore: AppStore
var body: some View {
ZStack {
Color.blue
if .game == self.appStore.appMode {
GameView()
} else if .options == self.appStore.appMode {
OptionsView()
} else {
MenuView()
}
}
}
}
我想為子視圖之間的切換設置動畫。 我見過一些使用狀態作為一個開關的例子,但我依賴的不止一個。 我還嘗試使用onAppear
和onDisappear
在子視圖中應用動畫。 這有效,但是當視圖未顯示時, onDisappear
不再執行。 此外,我想讓它適用於所有視圖。
有沒有辦法在不使用多個狀態的情況下做到這一點? 我喜歡只使用.transition
和.animation
。
現在我最好的解決方案是這個。
import SwiftUI
struct AppView: View {
@EnvironmentObject var appStore: AppStore
var body: some View {
ZStack {
Color.blue
if .game == self.appStore.appMode {
GameView()
.transition(.scale)
.zIndex(1) // to keep the views on top, however this needs to be changed when the active child view changes.
} else if .options == self.appStore.appMode {
OptionsView()
.transition(.scale)
.zIndex(2)
} else {
MenuView()
.transition(.scale)
.zIndex(3)
}
}
}
}
並且在每個視圖轉換器上。
.onTapGesture {
withAnimation(.easeInOut(duration: 2)) {
self.appStore.appMode = .game
}
}
使用以下方法,您可以根據需要修改您的appMode
(onAppear、onTapGesture 等)。 動畫持續時間當然可以任意設置(以及過渡類型,實際上,但是某些過渡在預覽中表現不佳,應該在模擬器或真實設備上進行測試)。
演示:(第一次閃爍只是預覽啟動,然后是 onAppear 的兩個過渡,然后是 onTap)
使用 Xcode 11.4 / iOS 13.4 進行測試 - 可以在預覽版和模擬器中使用。
代碼:重要部分標有內聯注釋。
var body: some View {
ZStack {
// !! to keep background deepest, `cause it affects removing transition
Color.blue.zIndex(-1)
// !! keep any view in explicit own `if` (don't use `else`)
if .game == self.appStore.appMode {
GameView()
.transition(AnyTransition.scale.animation(.easeInOut(duration: 1)))
}
if .options == self.appStore.appMode {
OptionsView()
.transition(AnyTransition.scale.animation(.easeInOut(duration: 1)))
}
if .menu == self.appStore.appMode {
MenuView()
.transition(AnyTransition.scale.animation(.easeInOut(duration: 1)))
}
}
}
更新:對於.slide
(可能還有其他移動轉換),狀態的變化應該被包裝成顯式withAnimation
,如下所示
withAnimation {
self.appStore.appMode = new_mode_here
}
注意:這些是預覽不支持的過渡之一 - 在模擬器中測試。
過渡示例
...
if .menu == self.appStore.appMode {
Text("MenuView").frame(width: 300, height: 100).background(Color.red)
.transition(AnyTransition.move(edge: .bottom).combined(with: .opacity).animation(.easeInOut(duration: 1)))
}
}
.onTapGesture {
withAnimation {
let next = self.appStore.appMode.rawValue + 1
self.appStore.appMode = next > 2 ? .game : AppStore.AppMode(rawValue: next)!
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.