首页 > 解决方案 > 如何保持动画在 TabView 视图变化上运行?

问题描述

我最近发现,当一个动画永远运行并且View通过 切换时TabView,动画状态会丢失。虽然这是预期的行为,但我想了解在 TabView 视图更改后,是否有办法在返回动画视图时保持动画运行?

这是一个简单的示例,展示了 SwiftUI 中的行为:

import SwiftUI

class MyState: ObservableObject {
    @Published var animate: Bool = false
}

struct ContentView: View {
    var body: some View {
        TabView {
            AnimationView()
                .tabItem {
                    Image(systemName: "eye")
                }
            Text("Some View")
                .tabItem {
                    Image(systemName: "play")
                }
        }
    }
}

struct AnimationView: View {
    @EnvironmentObject var myState: MyState
    var body: some View {
        VStack {
            Text(self.myState.animate ? "Animation running" : "Animation stopped")
                .padding()
            ZStack {
                Circle()
                    .stroke(style: StrokeStyle(lineWidth: 12.0))
                    .foregroundColor(Color.black)
                    .opacity(0.3)
                Circle()
                    .trim(
                        from: 0,
                        to: self.myState.animate ? 1.0 : 0.0
                    )
                    .stroke(
                        style: StrokeStyle(lineWidth: 12.0, lineCap: .round, lineJoin: .round)
                    )
                    .animation(
                        Animation
                            .linear(duration: self.myState.animate ? 1.0 : 0.0)
                            .repeatForever(autoreverses: false)
                    )

            }.frame(width: 200, height: 200)

            Button(action: {
                self.myState.animate.toggle()
            }) {
                Text("Toggle animation")
                .padding()
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
        .environmentObject(MyState())
    }
}

您可以在下面看到行为:

在此处输入图像描述

我期望控制的是回到动画运行的视图并查看它在当前时间的状态 - 这是,想象动画在切换视图时循环并返回视图找到它在“运行时间”或“实时”的正确点。

Obs:状态在视图中处理MyStateEnvironmentObject它不是本地(@State)

标签: swiftswiftui

解决方案


所以我添加了一个额外的参数来MyState存储用户在选项卡之间切换时的当前动画状态。以下是更新后的代码。我还在代码中添加了注释以便更好地理解。

class MyState: ObservableObject {
    @Published var animate: Bool = false
    var isAnimationActive = false // Store animate status when user switches between tabs
}

struct AnimationView: View {
    @EnvironmentObject var myState: MyState
    var body: some View {
        VStack {
            Text(self.myState.animate ? "Animation running" : "Animation stopped")
                .padding()
            ZStack {
                Circle()
                    .stroke(style: StrokeStyle(lineWidth: 12.0))
                    .foregroundColor(Color.black)
                    .opacity(0.3)
                Circle()
                    .trim(
                        from: 0,
                        to: self.myState.animate ? 1.0 : 0.0
                )
                    .stroke(
                        style: StrokeStyle(lineWidth: 12.0, lineCap: .round, lineJoin: .round)
                )
                    .animation(
                        Animation
                            .linear(duration: self.myState.animate ? 1.0 : 0.0)
                            .repeatForever(autoreverses: false)
                )

            }.frame(width: 200, height: 200)

            Button(action: {
                self.myState.animate.toggle()
            }) {
                Text("Toggle animation")
                    .padding()
            }
        }
        .onAppear(perform: {
            if self.myState.isAnimationActive {
                /*switching the animation inside withAnimation block is important*/
                withAnimation {
                    self.myState.animate = true
                }
            }
        })
            .onDisappear {
                self.myState.isAnimationActive = self.myState.animate
                /*The property needs to be set to false as SwiftUI compare the
                 views before re-rendering them*/
                self.myState.animate = false
        }
    }
}

推荐阅读