【问题标题】:How to keep the animation running on TabView View change?如何保持动画在 TabView 视图变化上运行?
【发布时间】:2020-05-26 20:03:25
【问题描述】:

我最近发现当一个动画永远运行并且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)

【问题讨论】:

    标签: swift swiftui


    【解决方案1】:

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

    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
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      经过一些测试,到目前为止我发现的最佳解决方案是遵循我在下面陈述的一些规则。请记住,这仅在您可以及时跟踪确切的动画位置时才有用。所以请检查下面的过程:

      1) 停止动画.onDisappear

      原因是具有动画元素的视图之间的状态变化会导致意想不到的行为,例如,元素定位完全关闭等等。

      self.myState.animate = false
      

      2) 跟踪进度

      我的用例是一个从 0 开始到 X 结束的长计算,MyState 具有在计算中为我提供current position 的方法。然后在* 0 到 1 的范围内计算此值,以便可以将其放入 SwiftUI Animation

      3) 跳转到特定时间

      SwiftUI Animation 尚不支持这部分,但假设您有一个需要 5 秒的动画,您的播放时间为 50%,所以您会跳到 2.5 秒开始播放.

      对此的实现,如果您以前使用过 Javascript,ActionScript 是 seek (https://greensock.com/docs/v2/Core/Animation/seek()) 的 GSAP 文档

      4) 重新触发动画

      我们首先通过改变状态来停止动画,为了让 SwiftUI 启动动画,我们在这个阶段需要做的就是再次改变状态

      self.myState.animate = true
      

      可能还有其他方法可以让动画保持运行,但在撰写本文时还没有发现它的文档,因此需要“从任意点开始动画”。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-01-04
        • 2021-03-22
        • 2020-04-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多