簡體   English   中英

如何在 SwiftUI 中為視圖之間的過渡設置動畫?

[英]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()
            }
        }
    }
}

我想為子視圖之間的切換設置動畫。 我見過一些使用狀態作為一個開關的例子,但我依賴的不止一個。 我還嘗試使用onAppearonDisappear在子視圖中應用動畫。 這有效,但是當視圖未顯示時, 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)!
    }
}

演示2

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM