物理学ベースのモーションは、力に基づいて動きます。インタラクティビティと動きを導くそのような力の 1 つとして、ばねの力があります。ばねの力には、減衰と剛性という特性があります。スプリング ベースのアニメーションでは、各フレームに適用されるばねの力に基づいて値と速度が計算されます。
アプリのアニメーションを一方向のみ遅くする場合は、代わりに摩擦ベースのフリング アニメーションを使用することを検討してください。
スプリング アニメーションのライフサイクル
スプリング ベースのアニメーションでは、SpringForce
を使用して、ばねの剛性、減衰率、最終位置をカスタマイズできます。アニメーションが開始されるとすぐに、ばねの力によって各フレームのアニメーション値と速度が更新されます。アニメーションは、ばねの力が平衡に達するまで続きます。
たとえば画面上でアプリアイコンをドラッグし、その後アイコンから指を離すと、目には見えないものの馴染みのある力によってアイコンが元の位置に戻ります。
図 1 は、同様のばねの効果を示しています。円の中央にあるプラス記号(+)は、タップ操作で加えられる力を示します。

スプリング アニメーションをビルドする
アプリケーションのスプリング アニメーションをビルドする一般的な手順は次のとおりです。
- サポート ライブラリを追加する: スプリング アニメーション クラスを使用するには、サポート ライブラリをプロジェクトに追加する必要があります。
- スプリング アニメーションを作成する: 主な手順は、
SpringAnimation
クラスのインスタンスを作成して、モーション動作パラメータを設定することです。 - (オプション)リスナーを登録する: リスナーを登録して、アニメーション ライフサイクルの変更とアニメーション値の更新を確認します。
注: 更新リスナーは、アニメーション値の変更に関してフレーム単位での更新が必要な場合にのみ登録する必要があります。更新リスナーは、アニメーションが別のスレッドで実行される可能性を防止します。
- (オプション)リスナーを削除する: 使用しなくなったリスナーを削除します。
- (オプション)開始値を設定する: アニメーションの開始値をカスタマイズします。
- 値の範囲を設定する: アニメーション値の範囲を設定して、最小値と最大値の範囲内に制限します。
- (オプション)開始速度を設定する: アニメーションの開始速度を設定します。
- (オプション)ばねの特性を設定する: ばねの減衰率と剛性を設定します。
- (オプション)カスタム スプリングを作成する: デフォルトのスプリングを使用しない場合、またはアニメーション全体で共通のスプリングを使用する場合は、カスタム スプリングを作成します。
- アニメーションを開始する: スプリング アニメーションを開始します。
- (オプション)アニメーションをキャンセルする: ユーザーが突然アプリを終了した場合、またはビューが表示されなくなった場合に、アニメーションをキャンセルします。
次のセクションでは、スプリング アニメーションをビルドする一般的な手順について詳しく説明します。
サポート ライブラリを追加する
物理学ベースのサポート ライブラリを使用するには、次のようにサポート ライブラリをプロジェクトに追加する必要があります。
- アプリ モジュールの
build.gradle
ファイルを開きます。 サポート ライブラリを
dependencies
セクションに追加します。dependencies { def dynamicanimation_version = "1.0.0" implementation 'androidx.dynamicanimation:dynamicanimation:$dynamicanimation_version' }
このライブラリの現在のバージョンを表示するには、バージョンのページで Dynamicanimation に関する情報をご覧ください。
スプリング アニメーションを作成する
SpringAnimation
クラスを使用すると、オブジェクトのスプリング アニメーションを作成できます。スプリング アニメーションを作成するには、SpringAnimation
クラスのインスタンスを作成し、オブジェクト、アニメーション化するオブジェクトのプロパティ、アニメーションを停止させるばねの最終位置(オプション)を指定する必要があります。
注: スプリング アニメーションの作成時、ばねの最終位置はオプションです。ただし、アニメーションを開始する前に定義する必要があります。
Kotlin
val springAnim = findViewById<View>(R.id.imageView).let { img -> // Setting up a spring animation to animate the view’s translationY property with the final // spring position at 0. SpringAnimation(img, DynamicAnimation.TRANSLATION_Y, 0f) }
Java
final View img = findViewById(R.id.imageView); // Setting up a spring animation to animate the view’s translationY property with the final // spring position at 0. final SpringAnimation springAnim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y, 0);
スプリング ベースのアニメーションでは、ビュー オブジェクトの実際のプロパティを変更することで、画面上のビューをアニメーション化できます。システムで使用できるビューは次のとおりです。
ALPHA
: ビューのアルファ透明度を表します。デフォルトの値は 1(不透明)で、値 0 は完全な透明(非表示)を表します。TRANSLATION_X
、TRANSLATION_Y
、TRANSLATION_Z
: これらのプロパティは、レイアウト コンテナで設定されている左座標、上座標、高さからの差分として、ビューの位置を制御します。TRANSLATION_X
: 左座標を示します。TRANSLATION_Y
: 上座標を示します。TRANSLATION_Z
: ビューの高さに対する相対的な奥行きを示します。
ROTATION
、ROTATION_X
、ROTATION_Y
: これらのプロパティは、ピボット ポイントを中心とした 2D の回転(rotation
プロパティ)と 3D の回転を制御します。SCROLL_X
、SCROLL_Y
: これらのプロパティは、ソースの左端と上端のスクロール オフセットをピクセル単位で示します。また、ページのスクロール量を位置で示します。SCALE_X
、SCALE_Y
: これらのプロパティは、ピボット ポイントを中心としたビューの 2D スケーリングを制御します。X
、Y
、Z
: コンテナ内のビューの最終位置を示す基本的なユーティリティ プロパティです。X
は、左の値とTRANSLATION_X
の合計です。Y
は、上の値とTRANSLATION_Y
の合計です。Z
は、高さ値とTRANSLATION_Z
の合計です。
リスナーを登録する
DynamicAnimation
クラスは、2 つのリスナー(OnAnimationUpdateListener
と OnAnimationEndListener
)を提供します。これらのリスナーは、アニメーション値の変更やアニメーションの終了など、アニメーションの更新をリッスンします。
OnAnimationUpdateListener
複数のビューをアニメーション化してチェーン アニメーションを作成する場合は、現在のビューのプロパティに変更があるたびにコールバックを受け取るように OnAnimationUpdateListener
を設定できます。コールバックは、現在のビューのプロパティで発生した変更に基づいて、ばねの位置を更新するように、他のビューに通知します。リスナーを登録する手順は次のとおりです。
-
addUpdateListener()
メソッドを呼び出し、リスナーをアニメーションにアタッチします。注: アニメーションを開始する前に、更新リスナーを登録する必要があります。ただし、更新リスナーは、アニメーション値の変更に関してフレーム単位での更新が必要な場合にのみ登録する必要があります。更新リスナーは、アニメーションが別のスレッドで実行される可能性を防止します。
-
onAnimationUpdate()
メソッドをオーバーライドして、現在のオブジェクトの変更を呼び出し元に通知します。次のサンプルコードは、OnAnimationUpdateListener
の全体的な使用方法を示しています。
Kotlin
// Setting up a spring animation to animate the view1 and view2 translationX and translationY properties val (anim1X, anim1Y) = findViewById<View>(R.id.view1).let { view1 -> SpringAnimation(view1, DynamicAnimation.TRANSLATION_X) to SpringAnimation(view1, DynamicAnimation.TRANSLATION_Y) } val (anim2X, anim2Y) = findViewById<View>(R.id.view2).let { view2 -> SpringAnimation(view2, DynamicAnimation.TRANSLATION_X) to SpringAnimation(view2, DynamicAnimation.TRANSLATION_Y) } // Registering the update listener anim1X.addUpdateListener { _, value, _ -> // Overriding the method to notify view2 about the change in the view1’s property. anim2X.animateToFinalPosition(value) } anim1Y.addUpdateListener { _, value, _ -> anim2Y.animateToFinalPosition(value) }
Java
// Creating two views to demonstrate the registration of the update listener. final View view1 = findViewById(R.id.view1); final View view2 = findViewById(R.id.view2); // Setting up a spring animation to animate the view1 and view2 translationX and translationY properties final SpringAnimation anim1X = new SpringAnimation(view1, DynamicAnimation.TRANSLATION_X); final SpringAnimation anim1Y = new SpringAnimation(view1, DynamicAnimation.TRANSLATION_Y); final SpringAnimation anim2X = new SpringAnimation(view2, DynamicAnimation.TRANSLATION_X); final SpringAnimation anim2Y = new SpringAnimation(view2, DynamicAnimation.TRANSLATION_Y); // Registering the update listener anim1X.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() { // Overriding the method to notify view2 about the change in the view1’s property. @Override public void onAnimationUpdate(DynamicAnimation dynamicAnimation, float value, float velocity) { anim2X.animateToFinalPosition(value); } }); anim1Y.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() { @Override public void onAnimationUpdate(DynamicAnimation dynamicAnimation, float value, float velocity) { anim2Y.animateToFinalPosition(value); } });
OnAnimationEndListener
OnAnimationEndListener
は、アニメーションの終了を通知します。アニメーションが平衡に達するかキャンセルされときにコールバックを受け取るように、リスナーを設定できます。リスナーを登録する手順は次のとおりです。
-
addEndListener()
メソッドを呼び出し、リスナーをアニメーションにアタッチします。 -
onAnimationEnd()
メソッドをオーバーライドして、アニメーションが平衡に達するかキャンセルされたときに通知を受け取るようにします。
リスナーを削除する
アニメーション更新コールバックとアニメーション終了コールバックの受信を停止するには、それぞれ removeUpdateListener()
メソッドと removeEndListener()
メソッドを呼び出します。
アニメーション開始値を設定する
アニメーションの開始値を設定するには、setStartValue()
メソッドを呼び出し、アニメーションの開始値を渡します。開始値を設定しない場合、アニメーションはオブジェクトのプロパティの現在値を開始値として使用します。
アニメーションの値の範囲を設定する
プロパティ値を特定の範囲に制限する場合は、アニメーションの最小値と最大値を設定できます。また、アルファ(0 から 1)などの固有の範囲を持つプロパティをアニメーション化する場合にも、範囲の制御に役立ちます。
-
最小値を設定するには、
setMinValue()
メソッドを呼び出し、プロパティの最小値を渡します。 -
最大値を設定するには、
setMaxValue()
メソッドを呼び出し、プロパティの最大値を渡します。
どちらのメソッドも、値が設定されているアニメーションを返します。
注: 開始値を設定し、アニメーション値の範囲を定義した場合は、開始値が最小値と最大値の範囲内にあることを確認してください。
開始速度を設定する
開始速度は、アニメーションの開始時にアニメーション プロパティが変更される速さを定義します。デフォルトの開始速度は 0 ピクセル/秒に設定されています。タップ操作の速度を使用するか、開始速度として固定値を使用することで、速度を設定できます。固定値を指定する場合は、dp/秒で値を定義してからピクセル/秒に変換することをおすすめします。dp/秒で値を定義すると、速度は密度とフォーム ファクタに依存しなくなります。値をピクセル/秒に変換する方法の詳細については、dp/秒をピクセル/秒に変換するのセクションをご覧ください。
速度を設定するには、setStartVelocity()
メソッドを呼び出し、ピクセル/秒で速度を渡します。このメソッドは、速度が設定されているばねの力のオブジェクトを返します。
注: タップ操作の速度の取得と計算を行うには、GestureDetector.OnGestureListener
または VelocityTracker
クラスメソッドを使用します。
Kotlin
findViewById<View>(R.id.imageView).also { img -> SpringAnimation(img, DynamicAnimation.TRANSLATION_Y).apply { … // Compute velocity in the unit pixel/second vt.computeCurrentVelocity(1000) val velocity = vt.yVelocity setStartVelocity(velocity) } }
Java
final View img = findViewById(R.id.imageView); final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y); … // Compute velocity in the unit pixel/second vt.computeCurrentVelocity(1000); float velocity = vt.getYVelocity(); anim.setStartVelocity(velocity);
dp/秒をピクセル/秒に変換する
ばねの速度は、ピクセル/秒である必要があります。速度の開始値として固定値を指定する場合は、dp/秒で値を指定してから、ピクセル/秒に変換します。変換には、TypedValue
クラスの applyDimension()
メソッドを使用します。次のサンプルコードをご覧ください。
Kotlin
val pixelPerSecond: Float = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpPerSecond, resources.displayMetrics)
Java
float pixelPerSecond = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpPerSecond, getResources().getDisplayMetrics());
ばねの特性を設定する
SpringForce
クラスは、ばねの各特性(減衰率や剛性など)のゲッター メソッドとセッター メソッドを定義します。ばねの特性を設定するには、ばねの力のオブジェクトを取得するか、特性を設定できるカスタムのばねの力を作成する必要があります。カスタムのばねの力を作成する方法の詳細については、カスタムのばねの力を作成するのセクションをご覧ください。
ヒント: セッター メソッドを使用している間は、すべてのセッター メソッドがばねの力のオブジェクトを返すため、メソッド チェーンを作成できます。
減衰率
減衰率は、ばねの振動の漸進的な減少を表します。減衰率を使用すると、ある跳ね返りから次の跳ね返りまでの、振動が減衰する速さを定義できます。ばねを減衰させる方法は 4 つあります。
- 過減衰は、減衰率が 1 より大きい場合に発生します。オブジェクトを静止位置にすばやく戻せます。
- 臨界減衰は、減衰率が 1 に等しい場合に発生します。オブジェクトを静止位置に最短時間で戻せます。
- 不足減衰は、減衰比が 1 未満の場合に発生します。オブジェクトが静止位置を通過して複数回オーバーシュートし、徐々に静止位置に達します。
- 非減衰は、減衰率が 0 に等しい場合に発生します。オブジェクトを永続的に振動させられます。
減衰率をばねに追加する手順は次のとおりです。
-
getSpring()
メソッドを呼び出してばねを取得し、減衰率を追加します。 -
setDampingRatio()
メソッドを呼び出し、ばねに追加する減衰率を渡します。このメソッドは、減衰率が設定されているばねの力のオブジェクトを返します。注: 減衰率は負でない数である必要があります。減衰率を 0 に設定した場合、ばねが静止位置に達することはありません。つまり、永続的に振動します。
システムで使用できる減衰率定数は次のとおりです。
DAMPING_RATIO_HIGH_BOUNCY
DAMPING_RATIO_MEDIUM_BOUNCY
DAMPING_RATIO_LOW_BOUNCY
DAMPING_RATIO_NO_BOUNCY
図 2: 高反発
図 3: 中反発
図 4: 低反発
図 5: 無反発
デフォルトの減衰率は DAMPING_RATIO_MEDIUM_BOUNCY
に設定されています。
Kotlin
findViewById<View>(R.id.imageView).also { img -> SpringAnimation(img, DynamicAnimation.TRANSLATION_Y).apply { … //Setting the damping ratio to create a low bouncing effect. spring.dampingRatio = SpringForce.DAMPING_RATIO_LOW_BOUNCY … } }
Java
final View img = findViewById(R.id.imageView); final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y); … //Setting the damping ratio to create a low bouncing effect. anim.getSpring().setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY); …
剛性
剛性は、ばねの強さを測るばね定数を定義します。硬いばねは、ばねが静止位置にないとき、アタッチされているオブジェクトに大きな力を加えます。剛性をばねに追加する手順は次のとおりです。
-
getSpring()
メソッドを呼び出してばねを取得し、剛性を追加します。 -
setStiffness()
メソッドを呼び出し、ばねに追加する剛性値を渡します。このメソッドは、剛性が設定されているばねの力のオブジェクトを返します。注: 剛性は正の数である必要があります。
システムで使用できる剛性定数は次のとおりです。
図 6: 高剛性
図 7: 中剛性
図 8: 低剛性
図 9: 超低剛性
デフォルトの剛性は STIFFNESS_MEDIUM
に設定されています。
Kotlin
findViewById<View>(R.id.imageView).also { img -> SpringAnimation(img, DynamicAnimation.TRANSLATION_Y).apply { … //Setting the spring with a low stiffness. spring.stiffness = SpringForce.STIFFNESS_LOW … } }
Java
final View img = findViewById(R.id.imageView); final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y); … //Setting the spring with a low stiffness. anim.getSpring().setStiffness(SpringForce.STIFFNESS_LOW); …
カスタムのばねの力を作成する
デフォルトのばねの力を使用する代わりに、カスタムのばねの力を作成できます。カスタムのばねの力を使用すると、複数のスプリング アニメーションで同じばねの力のインスタンスを共有できます。ばねの力を作成したら、減衰率や剛性などの特性を設定できます。
-
SpringForce
オブジェクトを作成します。SpringForce force = new SpringForce();
-
各メソッドを呼び出してプロパティを割り当てます。メソッド チェーンを作成することもできます。
force.setDampingRatio(DAMPING_RATIO_LOW_BOUNCY).setStiffness(STIFFNESS_LOW);
setSpring()
メソッドを呼び出して、ばねをアニメーションに設定します。setSpring(force);
アニメーションを開始する
スプリング アニメーションを介しする方法は 2 つあります。start()
をメソッドを呼び出す方法と、animateToFinalPosition()
メソッドを呼び出す方法です。どちらのメソッドも、メインスレッドで呼び出す必要があります。
animateToFinalPosition()
メソッドは、タスクを 2 つ実行します。
- ばねの最終位置を設定します。
- アニメーションが開始されていない場合、開始します。
このメソッドは、ばねの最終位置を更新し、必要に応じてアニメーションを開始するため、アニメーションの経過をいつでも変更できます。たとえばチェーン スプリング アニメーションでは、あるビューのアニメーションが別のビューに依存します。このようなアニメーションには、animateToFinalPosition()
メソッドを使用すると便利です。チェーン スプリング アニメーションでこのメソッドを使用すると、次に更新するアニメーションが現在実行中であるかどうかを心配せずに済みます。
図 10 は、チェーン スプリング アニメーションを示しています。あるビューのアニメーションが別のビューに依存しています。

animateToFinalPosition()
メソッドを使用するには、animateToFinalPosition()
メソッドを呼び出し、ばねの静止位置を渡します。setFinalPosition()
メソッドを呼び出すことで、ばねの静止位置を設定することもできます。
start()
メソッドは、プロパティ値をすぐに開始値に設定するわけではありません。プロパティ値はアニメーション パルスごとに変化します。これは描画パスの前に発生します。その結果、値がすぐに設定されたかのように、変更が次のフレームに反映されます。
Kotlin
findViewById<View>(R.id.imageView).also { img -> SpringAnimation(img, DynamicAnimation.TRANSLATION_Y).apply { … //Starting the animation start() … } }
Java
final View img = findViewById(R.id.imageView); final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y); … //Starting the animation anim.start(); …
アニメーションをキャンセルする
アニメーションをキャンセルまたは最後までスキップできます。アニメーションをキャンセルまたは最後までスキップする必要がある状況としては、ユーザー操作によってアニメーションをすぐに終了する必要がある場合が考えられます。これは主に、ユーザーがアプリを突然終了した場合、またはビューが非表示になった場合です。
アニメーションを終了するために使用できるメソッドは 2 つあります。cancel()
メソッドは、アニメーションを指定した位置の値で終了します。skipToEnd()
メソッドは、アニメーションを最後の値にスキップして終了します。
アニメーションを終了する前に、ばねの状態を最初に確認することが重要です。状態が非減衰の場合、アニメーションが静止位置に達することはありません。ばねの状態を確認するには、canSkipToEnd()
メソッドを呼び出します。ばねが減衰している場合、このメソッドは true
を返し、それ以外の場合は false
を返します。
ばねの状態がわかったら、skipToEnd()
メソッドまたは cancel()
メソッドを使用してアニメーションを終了できます。cancel()
メソッドは、メインスレッドでのみ呼び出す必要があります。
注: 一般に、skipToEnd()
メソッドでは表示のジャンプが発生します。