如何在 SwiftUI 中为视图之间的过渡设置动画? [英] How to animate transition between views in SwiftUI?

查看:42
本文介绍了如何在 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 不再被执行.此外,我想让它适用于所有视图.

I want to animate the switching between the child views. I have seen some examples using a state for one switch, but I'm relying on more than one. I also tried to apply the animation inside a child view with onAppear and onDisappear. That works, but when the view is not shown, the onDisappear does not get executed anymore. Besides, I would like to make it work for all the views.

有没有办法在不使用多个状态的情况下做到这一点?我只想使用 .transition.animation.

Is there any way to do this without using multiple states? I would love to use only .transition and .animation.

现在我最好的解决方案是这个.

Right now my best solution is this.

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 等).动画持续时间当然可以任意设置(以及过渡的类型,实际上,但是有些过渡在预览中表现不佳,应该在模拟器或真实设备上进行测试).

With the following approach you can modify your appMode as you wish (onAppear, onTapGesture, etc.). Animation duration is, of course, can be set any you wish (as well as kind of transition, actually, however some transitions behaves bad in Preview, and should be tested on Simulator or real device).

演示:(第一次闪烁只是预览启动,然后是 onAppear 和 onTap 的两次转换)

Demo: (first blink is just Preview launch, then two transitions for onAppear, then for onTap)

使用 Xcode 11.4/iOS 13.4 进行测试 - 可在预览版和模拟器中运行.

Tested with Xcode 11.4 / iOS 13.4 - works and in Preview and in Simulator.

代码:重要部分用内联注释标记.

Code: Important parts marked with comments inline.

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,如下所示

Update: for .slide (and probably other moving transitions) the change of state should be wrapped into explicit withAnimation, like below

withAnimation {
    self.appStore.appMode = new_mode_here
}

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

Note: these is one of transitions that is not supported by Preview - test in Simulator.

过渡示例

    ...
    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)!
    }
}

这篇关于如何在 SwiftUI 中为视图之间的过渡设置动画?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆