8
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[SwiftUI] timingCurveを用いた緩急のあるアニメーション例と解説

Last updated at Posted at 2023-08-06

以前、このような物理法則っぽいLoadingのアニメーションを作成しました。

Screen Recording 2023-07-20 at 11.38.47.gif

これでは、AnimationにtimingCurveを使って、アニメーションに緩急をつけています。

timingCurveのドキュメント

解説

まず、もっと簡単な場合を考えてみましょう。

struct ProgressCircleExplain: View {
    @State private var animate = false
    
    var body: some View {
        ZStack {
            Circle() // Outer circle
                .frame(width: 250, height: 250)
                .foregroundColor(.gray)
                .opacity(0)
            
            Circle() // Single Moving circle
                .frame(width: 20, height: 20)
                .foregroundColor(Color.blue)
                .offset(y: 50) // Set the radius of the outer circle here
                .rotationEffect(.degrees(self.animate ? 360 : 0))
                .animation(
                    Animation
                        .timingCurve(0.1, 0.7, 0.9, 0.2, duration: 1.9)
                        .repeatForever(autoreverses: false)
                )
            .onAppear() {
                self.animate = true
            }
        }
    }
}

これは、一個の円が円を描いて開店するアニメーションのコードです。

Screen Recording 2023-08-06 at 19.55.55.gif

等速で円周上を回転していますね。

これに、緩急をつけることで滑り落ちるようなアニメーションにします。

timingCurve はアニメーションに割り当てられる時間を、調整することができます。

実際に先ほどのコードにtimingCurveを適応したものを実装してみましょう。

struct ProgressCircleExplain: View {
    @State private var animate = false
    
    var body: some View {
        ZStack {
            Circle() // Outer circle
                .frame(width: 250, height: 250)
                .foregroundColor(.gray)
                .opacity(0)
            
            Circle() // Single Moving circle
                .frame(width: 20, height: 20)
                .foregroundColor(Color.blue)
                .offset(y: 50) // Set the radius of the outer circle here
                .rotationEffect(.degrees(self.animate ? 360 : 0))
                .animation(
                    Animation
                        .timingCurve(0.1, 0.7, 0.9, 0.2, duration: 1.9)
                        .repeatForever(autoreverses: false)
                )
            .onAppear() {
                self.animate = true
            }
        }
    }
}

これを動かすと以下のようになります。

Screen Recording 2023-08-06 at 20.00.54.gif

今回のアニメーションは以下のように図示することができます。

Frame 2.png

今回のアニメーションの円運動は、0~360°まで変異させることで、円周上を移動するアニメーションを実装しています。

滑り落ちる挙動にしたければ、降っている状態では、時間の進みが早く、上りの時に遅くなるようにすればそれに近づけれます。

そこで使用するのがtimingCurveです。

timingCurveはアニメーションを分割し、それらにかかる時間を調整することが可能です。

今回は

.timingCurve(0.1, 0.7, 0.9, 0.2, duration: 1.9)

を使用しています。これは
0~90°は0.1秒で処理をする。
90~180°は0.7秒で処理をする。
180~270°は0.9秒で処理をする。
270~360°は0.2秒で処理をする。

という表現になります。

Frame 1.png

図解するとこのようになります。

時間の総和はDurationと一致するようにしないと、アニメーションを行うたびにずれてしまうため、注意しましょう。

まとめ

このような自然法則っぽいアニメーションは実装が難しそうですが、timingCurveを使うことで簡単に再現することができました。

これでおしゃれなアニメーションを作ってみてくださいね

いいね、ブックマーク、フォローしていただけると勉強の励みになりますので是非お願いします。😉

追伸 --

Twitterで日々の学習風景を投稿してます。

@Ren_yello

8
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?