以物理為基礎的動作是由力所驅動。彈簧彈力就是其中一種力,可引導互動和動作。彈力具有下列屬性: 阻尼和勁度。在以彈簧為基礎的動畫中,值和速度是根據套用至每個影格的彈力計算。
如果只想讓應用程式的動畫在一個方向減速,請考慮改用基於摩擦力的快速滑過動畫。
彈簧效果的生命週期
在以彈簧為基礎的動畫中,SpringForce
類別可讓您自訂彈簧的硬度、阻尼比和最終位置。動畫開始後,彈簧力會在每個影格更新動畫值和速度。動畫會持續播放,直到彈簧力達到平衡為止。
舉例來說,如果您在畫面上拖曳某個應用程式圖示,然後移開手指以便放開應用程式圖示,該圖示就會以肉眼不可見但熟悉的力量移回原本的位置。
圖 1 顯示類似的彈簧效果。圓圈中間的加號 (+) 表示透過觸控手勢施加的力道。

建構彈簧效果動畫
為應用程式建構彈簧效果的一般步驟如下:
- 新增支援程式庫 如要使用彈簧效果類別,必須將支援程式庫新增至專案。
- 建立彈簧效果:
主要步驟是建立
SpringAnimation類別的執行個體,並設定動態行為參數。 - (選用) 註冊事件監聽器:
註冊事件監聽器,監看動畫生命週期變化和動畫值更新。
注意:只有在需要根據動畫值變化逐影格更新時,才應註冊更新事件監聽器。更新事件監聽器可防止動畫在個別執行緒上執行。
- (選用) 移除監聽器: 移除不再使用的監聽器。
- (選用) 設定起始值: 自訂動畫起始值。
- (選用) 設定值範圍: 設定動畫值範圍,將值限制在最小值和最大值範圍內。
- (選用) 設定起始速度: 設定動畫的起始速度。
- (選用) 設定彈簧屬性: 設定彈簧的阻尼比和勁度。
- (選用) 建立自訂彈簧: 如果您不打算使用預設彈簧,或想在整個動畫中使用通用彈簧,請建立自訂彈簧。
- 開始播放動畫: 開始播放彈簧效果。
- (選用) 取消動畫: 如果使用者突然結束應用程式或檢視畫面變得不可見,請取消動畫。
以下各節將詳細討論建構彈簧動畫的一般步驟。
新增支援程式庫
如要使用以物理為基礎的支援資料庫,請按照下列步驟將支援資料庫新增至專案:
- 開啟應用程式模組的
build.gradle檔案。 將支援資料庫新增至
dependencies區段。Groovy
dependencies { def dynamicanimation_version = '1.0.0' implementation "androidx.dynamicanimation:dynamicanimation:$dynamicanimation_version" }
Kotlin
dependencies { val 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: 代表檢視區塊的 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 類別提供兩個接聽程式: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() 方法並傳遞動畫的起始值。如未設定起始值,動畫會使用物件屬性的目前值做為起始值。
設定動畫值範圍
如要將屬性值限制在特定範圍內,可以設定動畫的最小值和最大值。此外,如果動畫屬性具有內建範圍 (例如 Alpha 值介於 0 到 1 之間),這個函式也有助於控制範圍。
-
如要設定最小值,請呼叫
setMinValue()方法,並傳遞屬性的最小值。 -
如要設定最大值,請呼叫
setMaxValue()方法,並傳遞屬性的最大值。
這兩種方法都會傳回要設定值的動畫。
注意:如果已設定起始值並定義動畫值範圍,請確保起始值介於最小值和最大值範圍之間。
設定初速度
起始速度會定義動畫屬性在動畫開始時的變化速度。預設的起始速度為每秒零像素。你可以使用觸控手勢的速度設定速度,也可以使用固定值做為起始速度。如果選擇提供固定值,建議您以每秒 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());
設定 Spring 屬性
SpringForce 類別會為每個彈簧屬性 (例如阻尼比和勁度) 定義 getter 和 setter 方法。如要設定彈簧屬性,請務必擷取彈簧力物件,或建立自訂彈簧力,以便設定屬性。如要進一步瞭解如何建立自訂彈簧力,請參閱「建立自訂彈簧力」一節。
提示:使用設定器方法時,您可以建立方法鏈,因為所有設定器方法都會傳回彈簧力物件。
阻尼比
阻尼比描述彈簧震盪的逐漸減少。您可以使用阻尼比定義震盪從一次彈跳到下一次的衰減速度。有四種不同的方法可以阻尼彈簧:
- 當阻尼比大於 1 時,就會發生過阻尼。可讓物件輕輕回到靜止位置。
- 當阻尼比等於 1 時,就會發生臨界阻尼。可讓物件在最短時間內回到靜止位置。
- 阻尼比小於 1 時,就會發生欠阻尼現象。傳遞其餘位置時,物件會多次超出目標位置,然後逐漸達到其餘位置。
- 當阻尼比等於零時,就會發生無阻尼現象。可讓物件永遠震盪。
如要為彈簧新增阻尼比,請執行下列步驟:
-
呼叫
getSpring()方法來擷取彈簧,並新增阻尼比。 -
呼叫
setDampingRatio()方法,並傳遞要新增至彈簧的阻尼比。這個方法會傳回設定阻尼比的彈簧力物件。注意:阻尼比必須為非負數。如果將阻尼比設為零,彈簧永遠不會達到靜止位置。換句話說,它會永遠震盪。
系統提供下列阻尼比常數:
DAMPING_RATIO_HIGH_BOUNCYDAMPING_RATIO_MEDIUM_BOUNCYDAMPING_RATIO_LOW_BOUNCYDAMPING_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);
開始播放動畫
啟動彈簧效果的方法有兩種:呼叫 start() 或 animateToFinalPosition() 方法。這兩個方法都必須在主執行緒上呼叫。
animateToFinalPosition()
方法會執行兩項工作:
- 設定彈簧的最終位置。
- 如果動畫尚未開始,則啟動動畫。
由於這個方法會更新彈簧的最終位置,並視需要啟動動畫,因此您可以隨時呼叫這個方法來變更動畫的過程。舉例來說,在鏈結彈簧效果中,一個檢視區塊的動畫取決於另一個檢視區塊。對於這類動畫,使用 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(); …
取消動畫
你可以取消或跳到動畫結尾。如果使用者互動要求立即終止動畫,您就必須取消或跳到動畫結尾。這通常發生在使用者突然結束應用程式,或檢視畫面變成隱藏狀態時。
終止動畫的方法有兩種。
cancel() 方法會在動畫目前的值終止動畫。skipToEnd() 方法會將動畫跳至最終值,然後終止動畫。
終止動畫前,請務必先檢查彈簧的狀態。如果狀態未阻尼,動畫就永遠無法達到靜止位置。
如要查看彈簧狀態,請呼叫 canSkipToEnd() 方法。如果彈簧已阻尼,此方法會傳回 true,否則會傳回 false。
瞭解彈簧的狀態後,您可以使用 skipToEnd() 方法或 cancel() 方法終止動畫。cancel() 方法只能在主執行緒上呼叫。
附註:一般而言,skipToEnd() 方法會造成視覺跳動。