如何在 SwiftUI 中为视图之间的过渡设置动画?

spa*_*ora 5 swift 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()
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我想为子视图之间的切换设置动画。我见过一些使用状态作为一个开关的例子,但我依赖的不止一个。我还尝试在子视图中使用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)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

并且在每个视图转换器上。

.onTapGesture {
    withAnimation(.easeInOut(duration: 2)) {
        self.appStore.appMode = .game
    }
}
Run Code Online (Sandbox Code Playgroud)

Asp*_*eri 7

使用以下方法,您可以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)))
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

更新:对于.slide(可能还有其他移动转换)状态的变化应该被包装成显式withAnimation,如下所示

withAnimation {
    self.appStore.appMode = new_mode_here
}
Run Code Online (Sandbox Code Playgroud)

注意:这些是预览不支持的过渡之一 - 在模拟器中测试。

过渡示例

withAnimation {
    self.appStore.appMode = new_mode_here
}
Run Code Online (Sandbox Code Playgroud)

演示2

  • 我仍然在理解答案的过程中。但是,你追求的是分数,仅此而已。干得好。 (7认同)
  • 如果它*适合您*,我可以问您为什么不接受答案吗? (2认同)