【问题标题】:Chaining animations in SwiftUI在 SwiftUI 中链接动画
【发布时间】:2019-07-05 17:44:19
【问题描述】:

我正在 SwiftUI 中制作一个相对复杂的动画,我想知道链接各个动画阶段的最佳/最优雅的方式是什么。

假设我有一个首先需要缩放的视图,然后等待几秒钟然后淡出(然后等待几秒钟并重新开始 - 无限期地)。

如果我尝试在同一个视图/堆栈上使用多个 withAnimation() 块,它们最终会相互干扰并弄乱动画。

到目前为止,我能想到的最好的方法是在初始视图 .onAppear() 修饰符上调用自定义函数,并在该函数中为动画的每个阶段设置 withAnimation() 块,并在它们之间设置延迟。所以,它基本上看起来像这样:

func doAnimations() {
  withAnimation(...)

  DispatchQueue.main.asyncAfter(...)
    withAnimation(...)

  DispatchQueue.main.asyncAfter(...)
    withAnimation(...)

  ...

}

它最终会变得很长而且不是很“漂亮”。我确信必须有更好/更好的方法来做到这一点,但到目前为止我尝试的一切都没有给我想要的确切流程。

任何想法/建议/提示将不胜感激。谢谢!

【问题讨论】:

    标签: animation swiftui xcode11 ios13


    【解决方案1】:

    正如其他回复中提到的,目前 SwiftUI 中没有链接动画的机制,但您不一定需要使用手动计时器。相反,您可以在链式动画上使用delay 函数:

    withAnimation(Animation.easeIn(duration: 1.23)) {
        self.doSomethingFirst()
    }
    
    withAnimation(Animation.easeOut(duration: 4.56).delay(1.23)) {
        self.thenDoSomethingElse()
    }
    
    withAnimation(Animation.default.delay(1.23 + 4.56)) {
        self.andThenDoAThirdThing()
    }
    
    

    我发现与使用 DispatchQueueTimer 相比,这会导致更一致地更平滑的链接动画,这可能是因为它对所有动画使用相同的调度程序。

    同时处理所有延迟和持续时间可能很麻烦,因此雄心勃勃的开发人员可能会将计算抽象到某个全局 withChainedAnimation 函数中,而不是为您处理。

    【讨论】:

      【解决方案2】:

      使用计时器有效。这是我自己的项目:

      @State private var isShowing = true
      @State private var timer: Timer?
      
      ...
      
      func askQuestion() {
          withAnimation(Animation.easeInOut(duration: 1).delay(0.5)) {
              isShowing.toggle()
          }
          timer = Timer.scheduledTimer(withTimeInterval: 1.6, repeats: false) { _ in
              withAnimation(.easeInOut(duration: 1)) {
                  self.isShowing.toggle()
              }
              self.timer?.invalidate()
          }
      
          // code here executes before the timer is triggered.
      
      }
      

      【讨论】:

        【解决方案3】:

        恐怕暂时不支持关键帧之类的东西。至少他们可以添加onAnimationEnd()...但是没有这样的东西。

        我确实有一些运气,是动画形状路径。虽然没有关键帧,但您拥有更多控制权,因为您可以定义“AnimatableData”。例如,查看我对另一个问题的回答:https://stackoverflow.com/a/56885066/7786555

        在这种情况下,它基本上是一个旋转的弧线,但会从零增长到一定长度,并在转弯结束时逐渐回到零长度。动画有 3 个阶段:一开始,弧的一端移动,但另一端不移动。然后他们都以相同的速度一起移动,最后第二端到达第一端。我的第一种方法是使用 DispatchQueue 的想法,它奏效了,但我同意:它非常丑陋。然后我想知道如何正确使用 AnimatableData。所以......如果你正在为路径设置动画,那么你很幸运。否则,我们似乎不得不等待更优雅的代码的可能性。

        【讨论】:

        • 感谢您的快速回复。让我问你这个问题 - 如果你需要从另一个问题中获取动画,请在动画完成一个完整的循环时停止动画,然后淡出并重新开始动画。你能想出一种不添加 DispatchQueue 的方法吗?
        • 从我的脑海中,我想不出办法:-(我确实尝试同时设置两个动画,其中一个使用 animation().delay() 所以它会从第一个完成时开始。但我放弃了这个想法,因为我不是很成功。但也许这是你可以探索的东西。
        • 是的,我也尝试过,但运气不佳... :[再次感谢,祝我们大家好运... :]
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-09
        • 1970-01-01
        • 2022-01-01
        • 1970-01-01
        相关资源
        最近更新 更多