在SwiftUI中链接动画

时间:2019-07-05 17:44:19

标签: animation swiftui xcode11 ios13

我正在使用SwiftUI开发相对复杂的动画,并且想知道链接各个动画阶段的最好/最优雅的方法是什么。

假设我有一个观点,首先需要缩放,然后等待几秒钟,然后消失(然后等待几秒钟,然后无限期地重新开始)。

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

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

func doAnimations() {
  withAnimation(...)

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

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

  ...

}

它最终变得很长而不是很“漂亮”。我敢肯定必须有一种更好/更精巧的方法来做到这一点,但是到目前为止我所做的一切都没有给我我想要的确切流程。

任何想法/建议/技巧将不胜感激。谢谢!

3 个答案:

答案 0 :(得分:0)

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

我确实能碰运气的地方是给形状路径设置动画。尽管没有关键帧,但是您可以控制很多,因为您可以定义“ AnimatableData”。例如,检查我对另一个问题的回答:https://stackoverflow.com/a/56885066/7786555

在那种情况下,基本上是一个弧形旋转,但是从零开始增长到某个长度,并且在转弯结束时逐渐回到零长度。动画分为三个阶段:首先,弧的一端移动,但另一端不移动。然后他们俩以相同的速度一起移动,最后第二端到达第一端。我的第一种方法是使用DispatchQueue的想法,这个想法行得通,但是我同意:这非常丑陋。然后,我弄清楚如何正确使用AnimatableData。所以...如果您正在设置动画路径,那么您很幸运。否则,我们似乎不得不等待更优雅的代码的出现。

答案 1 :(得分:0)

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

@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.

}

答案 2 :(得分:0)

如其他响应中所述,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函数,而不是为您处理。