web-dev-qa-db-ja.com

SwiftUIでのアニメーションのチェーン

私はSwiftUIで比較的複雑なアニメーションに取り組んでおり、さまざまなアニメーションフェーズをチェーン化するための最良/最もエレガントな方法は何なのかと思っています。

最初にスケーリングする必要があるビューがあるとします。次に数秒待ってからフェードします(次に数秒待って最初からやり直す-無期限に)。

同じビュー/スタックで複数のwithAnimation()ブロックを使用しようとすると、それらは相互に干渉してアニメーションをめちゃくちゃにしてしまいます。

これまでに思いついた最高の方法は、初期ビューの.onAppear()修飾子でカスタム関数を呼び出し、その関数に、アニメーション間の各ステージにwithAnimation()ブロックを配置し、それらの間に遅延を設定することです。したがって、基本的には次のようになります。

func doAnimations() {
  withAnimation(...)

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

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

  ...

}

最終的にはかなり長くなり、あまり「きれい」ではありません。これを行うにはより良い/より良い方法が必要だと私は確信していますが、これまでに試みたすべてが私が望む正確なフローを与えませんでした。

任意のアイデア/推奨事項/ヒントをいただければ幸いです。ありがとう!

8
Rony Rozen

他の応答で述べたように、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()
}

これにより、DispatchQueueまたはTimerを使用するよりも一貫してスムーズなチェーンアニメーションが生成されることがわかりました。おそらく、すべてのアニメーションに同じスケジューラを使用しているためです。

すべての遅延と継続時間を調整するのは面倒な場合があるため、意欲的な開発者は、計算をいくつかのグローバルwithChainedAnimation関数に抽象化して処理するのではなく、.

3
marcprux

タイマーの使用は機能します。これは私自身のプロジェクトから:

@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
Hugo F

残念ながら、当分の間、キーフレームなどのサポートはありません。少なくとも彼らはonAnimationEnd()...を追加できたかもしれませんが、そのようなことはありません。

運が良かったのは、シェイプパスのアニメーションです。キーフレームはありませんが、「AnimatableData」を定義できるため、より細かく制御できます。例として、別の質問に対する私の回答を確認してください: https://stackoverflow.com/a/56885066/7786555

その場合、回転するのは基本的には弧ですが、ゼロからある程度の長さまで成長し、ターンの終了時に徐々にゼロの長さに戻ります。アニメーションには3つのフェーズがあります。最初は、弧の一方の端が動きますが、もう一方は動きません。次に、両方が同じ速度で移動し、最後に2番目の端が最初の端に到達します。私の最初のアプローチはDispatchQueueのアイデアを使用することでしたが、うまくいきましたが、私は同意します。それはひどく醜いです。次に、AnimatableDataを適切に使用する方法を理解します。だから...パスをアニメーション化している場合、あなたは運がいいです。それ以外の場合は、よりエレガントなコードの可能性を待つ必要があるようです。

0
kontiki