使用方式:View.animate() 後跟 translationX() 等方法,動畫會自動執行
。canvas
view.animate().translationX(500);
複製代碼
使用方式:bash
setter
方法的最後調用invalidate()
方法,刷新繪製;public class SportsView extends View {
float progress = 0;
......
// 建立 getter 方法
public float getProgress() {
return progress;
}
// 建立 setter 方法
public void setProgress(float progress) {
this.progress = progress;
invalidate();
}
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
......
canvas.drawArc(arcRectF, 135, progress * 2.7f, false, paint);
......
}
}
......
// 建立 ObjectAnimator 對象
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "progress", 0, 65);
// 執行動畫
animator.start();
複製代碼
給動畫設置監聽器,能夠在關鍵時刻獲得反饋,從而及時作出合適的操做,例如在動畫的屬性更新時同步更新其餘數據,或者在動畫結束後回收資源等。ide
設置監聽器的方法, ViewPropertyAnimator
和 ObjectAnimator
略微不同: ViewPropertyAnimator
用的是 setListener()
和 setUpdateListener()
方法,能夠設置一個監聽器
,要移除監聽器時經過 set[Update]Listener(null) 填 null 值來移除;而 ObjectAnimator
則是用 addListener()
和 addUpdateListener()
來添加一個或多個監聽器
,移除監聽器則是經過 remove[Update]Listener() 來指定移除對象。post
另外,因爲 ObjectAnimator
支持使用 pause()
方法暫停,因此它還多了一個 addPauseListener() / removePauseListener()
的支持; 而 ViewPropertyAnimator
則獨有 withStartAction()
和 withEndAction()
方法,能夠設置一次性的動畫開始或結束的監聽,在動畫執行結束後就自動丟棄,就算以後再重用 ViewPropertyAnimator
來作別的動畫,用它們設置的回調也不會再被調用。而 set/addListener() 所設置的 AnimatorListener 是持續有效的,當動畫重複執行時,回調總會被調用。性能
須要說明一下的是,就算動畫被取消,onAnimationEnd()
也會被調用。因此當動畫被取消時,若是設置了 AnimatorListener
,那麼 onAnimationCancel()
和 onAnimationEnd()
都會被調用。onAnimationCancel()
會先於 onAnimationEnd()
被調用。動畫
withEndAction()
設置的回調只有在動畫正常結束時纔會被調用,而在動畫被取消時不會被執行。這點和 AnimatorListener.onAnimationEnd()
的行爲是不一致的。ui
關於 ObjectAnimator
,上面講到能夠用 ofInt()
來作整數的屬性動畫和用ofFloat()
來作小數的屬性動畫。這兩種屬性類型是屬性動畫最經常使用的兩種,不過在實際的開發中,能夠作屬相動畫的類型仍是有其餘的一些類型。當須要對其餘類型來作屬性動畫的時候,就須要用到 TypeEvaluator
了。this
藉助於 TypeEvaluator
,屬性動畫就能夠經過 ofObject()
來對不限定類型的屬性作動畫了。方式很簡單:lua
private class PointFEvaluator implements TypeEvaluator<PointF> {
PointF newPoint = new PointF();
@Override
public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
float x = startValue.x + (fraction * (endValue.x - startValue.x));
float y = startValue.y + (fraction * (endValue.y - startValue.y));
newPoint.set(x, y);
return newPoint;
}
}
ObjectAnimator animator = ObjectAnimator.ofObject(view, "position",
new PointFEvaluator(), new PointF(0, 0), new PointF(1, 1));
animator.start();
複製代碼
不少時候,你在同一個動畫中會須要改變多個屬性,例如在改變透明度的同時改變尺寸。若是使用 ViewPropertyAnimator,你能夠直接用連寫的方式來在一個動畫中同時改變多個屬性:spa
view.animate()
.scaleX(1)
.scaleY(1)
.alpha(1);
複製代碼
使用 PropertyValuesHolder
來同時在一個ObjectAnimator
動畫中改變多個屬性。
PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("scaleX", 1);
PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("scaleY", 1);
PropertyValuesHolder holder3 = PropertyValuesHolder.ofFloat("alpha", 1);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view, holder1, holder2, holder3)
animator.start();
複製代碼
有的時候,你不止須要在一個動畫中改變多個屬性,還會須要多個動畫配合工做,好比,在內容的大小從 0 放大到 100% 大小後開始移動。這種狀況使用 PropertyValuesHolder
是不行的,由於這些屬性若是放在同一個動畫中,須要共享動畫的開始時間、結束時間、Interpolator 等等一系列的設定,這樣就不能有前後次序地執行動畫了。
這就須要用到 AnimatorSet 了。
ObjectAnimator animator1 = ObjectAnimator.ofFloat(...);
animator1.setInterpolator(new LinearInterpolator());
ObjectAnimator animator2 = ObjectAnimator.ofInt(...);
animator2.setInterpolator(new DecelerateInterpolator());
AnimatorSet animatorSet = new AnimatorSet();
// 兩個動畫依次執行
animatorSet.playSequentially(animator1, animator2);
animatorSet.start();
// 兩個動畫同時執行
animatorSet.playTogether(animator1, animator2);
animatorSet.start();
// 使用 AnimatorSet.play(animatorA).with/before/after(animatorB)
// 的方式來精確配置各個 Animator 之間的關係
animatorSet.play(animator1).with(animator2);
animatorSet.play(animator1).before(animator2);
animatorSet.play(animator1).after(animator2);
animatorSet.start();
複製代碼
// 在 0% 處開始
Keyframe keyframe1 = Keyframe.ofFloat(0, 0);
// 時間通過 50% 的時候,動畫完成度 100%
Keyframe keyframe2 = Keyframe.ofFloat(0.5f, 100);
// 時間見過 100% 的時候,動畫完成度倒退到 80%,即反彈 20%
Keyframe keyframe3 = Keyframe.ofFloat(1, 80);
PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("progress", keyframe1, keyframe2, keyframe3);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view, holder);
animator.start();
複製代碼
額外簡單說一下 ValuesAnimator
。不少時候,你用不到它,只是在你使用一些第三方庫的控件,而你想要作動畫的屬性卻沒有 setter / getter
方法的時候,會須要用到它。
ValueAnimator 並不經常使用,由於它的功能太基礎了。ValueAnimator 是 ObjectAnimator 的父類,實際上,ValueAnimator 就是一個不能指定目標對象版本的 ObjectAnimator。
ObjectAnimator 是自動調用目標對象的 setter 方法來更新目標屬性的值,以及不少的時候還會以此來改變目標對象的 UI,而 ValueAnimator 只是經過漸變的方式來改變一個獨立的數據,這個數據不是屬於某個對象的,至於在數據更新後要作什麼事,全都由你來定,你能夠依然是去調用某個對象的 setter 方法(別這麼爲難本身),也能夠作其餘的事,無論要作什麼,都是要你本身來寫的,ValueAnimator 不會幫你作。
好比有的時候,你要給一個第三方控件作動畫,你須要更新的那個屬性沒有 setter 方法,只能直接修改,這樣的話 ObjectAnimator 就不靈了啊。怎麼辦?這個時候你就能夠用 ValueAnimator
,在它的 onUpdate()
裏面更新這個屬性的值,而且手動調用 invalidate()
。
因此,ViewPropertyAnimator、ObjectAnimator、ValueAnimator 這三種 Animator,它們實際上是一種遞進的關係:從左到右依次變得更加難用,也更加靈活。但我要說明一下,它們的性能是同樣的,由於 ViewPropertyAnimator 和 ObjectAnimator 的內部實現其實都是 ValueAnimator,ObjectAnimator 更是原本就是 ValueAnimator 的子類,它們三個的性能並無差異。它們的差異只是使用的便捷性以及功能的靈活性。因此在實際使用時候的選擇,只要遵循一個原則就行:儘可能用簡單的。
能用 View.animate() 實現就不用 ObjectAnimator,能用 ObjectAnimator 就不用 ValueAnimator。