物理動作由力驅動。彈力是引導互動和運動的力量之一。彈簧有以下屬性: 阻尼和硬度。在彈簧效果中,系統會根據每個影格套用的彈簧效果計算值和速率。
如果您希望應用程式動畫只朝一個方向放慢,請考慮改用以摩擦為主的快速滑過動畫。
彈簧效果的生命週期
在彈簧效果的動畫中,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") }
如要查看這個程式庫的目前版本,請參閱版本頁面中的動態動畫相關資訊。
建立彈簧效果
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()
方法並傳遞屬性值的最大值。
這兩種方法都會傳回要設定該值的動畫。
注意:如果您已設定起始值並定義動畫值範圍,請確保起始值在最小值和最大值範圍內。
設定啟動速度
「開始速度」是指動畫屬性在動畫開始時變更的速度。預設的啟動速度設為每秒 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
類別會定義每個彈簧屬性的 getter 和 setter 方法,例如阻尼比和硬度。如要設定彈簧屬性,請務必擷取彈簧力物件,或是建立能夠設定屬性的自訂彈力物件。如要進一步瞭解如何建立自訂彈簧,請參閱「建立自訂彈簧力」一節。
提示:使用 setter 方法時,您可以建立方法鏈結,因為所有 setter 方法都會傳回彈簧力物件。
阻尼比
阻尼比是指春天波動是逐漸降低的。使用阻尼比,您可以定義從一次跳轉到下次跳轉速度的衰減速度。有四種不同的方法可以消滅春季:
- 阻隔率大於 1 時,就會發生過度取樣的情形。如此一來,物件就能輕輕地回到剩下的位置。
- 阻隔率等於 1 時,會發生嚴重阻斷。可讓物件在最短時間內恢復為其餘位置。
- 阻隔率小於 1 時,就會發生不足區域。它會傳遞其餘位置,然後逐漸達到剩餘位置,讓物件多次過度拍攝。
- 阻隔率等於零時,就會發生未取樣情形。可讓物件永久閃爍。
如要將阻尼比加入彈簧,請按照下列步驟操作:
-
呼叫
getSpring()
方法以擷取彈簧,新增阻尼比。 -
呼叫
setDampingRatio()
方法,並傳遞要新增至春季的阻尼比。此方法會傳回已設定阻尼比的彈簧力物件。注意:取樣率「必須」不是負數。如果將阻尼比設為零,彈簧就不會達到剩餘的位置。換句話說,它會永遠閃爍。
系統提供下列阻尼比常數:
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);
開始動畫
您可以透過以下兩種方式啟動彈簧效果:呼叫 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()
方法會導致視覺跳轉。