如何在 SwiftUI 中停止当前状态的动画

Vik*_*iks 7 swift swiftui

你好,我编写了一个简单的代码,其中我创建了一个带有改变其位置的圆圈的动画。我希望当我点击该圆圈时动画停止,但无论我将动画设置为零,它都不会停止。也许我的方法在某种程度上是错误的。如果有人提供帮助,我会很高兴。

struct ContentView: View {
    @State private var enabled = true
    @State private var offset  = 0.0
    
    var body: some View {

        Circle()
            .frame(width: 100, height: 100)
            .offset(y: CGFloat(self.offset))
            .onAppear {
                withAnimation(self.enabled ? .easeIn(duration: 5) : nil) {
                    self.offset = Double(-UIScreen.main.bounds.size.height + 300)
                }
            }
            .onTapGesture {
                self.enabled = false
            }

    }
}
Run Code Online (Sandbox Code Playgroud)

ced*_*rwe 3

正如@Schottky 上面所说,该offset值已经被设置,SwiftUI只是动画更改。

\n

问题是,当您点击圆圈时,onAppear不会再次调用,这意味着enabled根本不会检查,即使是它也不会阻止offset动画。

\n

为了解决这个问题,我们可以引入一个Timer并做一些小的计算,iOS带有一个内置Timer类,可以让我们定期运行代码。所以代码看起来像这样:

\n
struct ContentView: View {\n    @State private var offset  = 0.0\n    // 1\n    let timer = Timer.publish(every: 0.1, on: .main, in: .common).autoconnect()\n    @State var animationDuration: Double = 5.0\n    var body: some View {\n        Circle()\n            .frame(width: 100, height: 100)\n            .offset(y: CGFloat(self.offset))\n            .onTapGesture {\n                // 2\n                timer.upstream.connect().cancel()\n            }\n            .onReceive(timer) { _ in\n                // 3\n                animationDuration -= 0.1\n                if animationDuration <= 0.0 {\n                    timer.upstream.connect().cancel()\n                } else {\n                    withAnimation(.easeIn) {\n                        self.offset += Double(-UIScreen.main.bounds.size.height + 300)/50\n                    }\n                }\n            }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  1. 这将创建一个计时器发布者,要求计时器每秒触发一次0.1。它说计时器应该在main线程上运行,它应该在common运行循环上运行,这是您\xe2\x80\x99大多数时间想要使用的循环。(运行循环可以iOS在用户主动执行某些操作(例如在列表中滚动或点击按钮)时处理正在运行的代码。)

    \n
  2. \n
  3. 当您点击圆圈时,计时器会自动取消。

    \n
  4. \n
  5. 我们需要使用名为 的新修饰符手动捕获公告(出版物)onReceive()。它接受发布者作为其第一个参数(在这里它是我们的计时器)和一个作为第二个参数运行的函数,并且它将确保每当发布者发送其更改通知时调用该函数(在这种情况下,每个0.1 秒)。

    \n
  6. \n
\n

每 0.1 秒后,我们减少动画的持续时间,当持续时间结束(duration = 0.0)时,我们停止计时器,否则我们继续减少offset.

\n

查看使用计时器重复触发事件以了解更多信息Timer

\n

  • 非常感谢您清晰的解释和精彩的回答! (3认同)