Android屬性動畫之ValueAnimator代碼詳解
屬性動畫通過改變一個對象的屬性值來進行動畫,屬性動畫包含了以下幾個特性:
1、持續(xù)時間(Duration)
主要用來定義動畫的持續(xù)時間,默認值為300ms。
2、時間插值器(Time interpolation)
指定時間變化的百分比,就是當前流逝時間除以指定的持續(xù)時間,這個可以自定義,繼承Interpolator,重寫getInterpolation方法。
3、重復(fù)次數(shù)和行為(Repeat count and behavior)
指定動畫的執(zhí)行次數(shù)和動畫的重復(fù)模式
4、動畫集(Animator sets)
可以把多個動畫放到一個集合中,是他們同時執(zhí)行,或者指定它們直接的順序和延遲。
5、Frame refresh delay(幀刷新延遲)
可以指定如何去刷新動畫的幀,默認是每10ms刷新一次,這個刷新也取決于系統(tǒng)的繁忙程度。
上面我們知道屬性動畫就是改變對象的屬性值來實現(xiàn)動畫,ValueAnimator的特點就是你不需要明確的指定你要改變的對象和屬性,你只需要得到一個動態(tài)的值來自己去設(shè)置相應(yīng)對象的屬性,也就是它就是提供屬性的變化值,你拿到這個值可以動態(tài)的更改對象屬性值??偨Y(jié)一句就是監(jiān)聽動畫過程,自己實現(xiàn)屬性的改變。
舉個例子:
// 這里指定了值的變化范圍 ValueAnimator animator = ValueAnimator.ofFloat(0, 500); // 這里指定變化持續(xù)時間 animator.setDuration(1000); //開始動畫 animator.start() //開始動畫后,我們可以動態(tài)的獲取變化值 animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { //根據(jù)變化值來設(shè)置imageView對象的Y軸坐標,這樣就實現(xiàn)了imageView的垂直移動 imageView.setTranslationY((Float) animation.getAnimatedValue()); } });
上面使用imageView.setTranslationY((Float) animation.getAnimatedValue())
來動態(tài)的改變圖片的translationY屬性,需要說明的是,如果在低版本中,我們使用的是NineOldAnimations這個庫,用法跟系統(tǒng)基本一致,在NineOldAnimations里面我們動態(tài)改變對象的屬性的時候,它提供了一個ViewHelper類,它是設(shè)置各種動畫值的幫助類,可以簡單的設(shè)置并應(yīng)用動畫值。所以在3.0以下版本中,使用ViewHelper來進行屬性值的改變,上面的設(shè)置等同如下:
ViewHelper.setTranslationX(imageView, (Float) animation.getAnimatedValue());
上面的過程如下圖所示:
上面的過程應(yīng)該比較清晰,在上面我們就設(shè)置了一個持續(xù)時間,下面我們可以來看看我們可以為ValueAnimator設(shè)置其他哪些東西。
public ObjectAnimator setDuration(long duration)
設(shè)置持續(xù)時間public void setEvaluator(TypeEvaluator value)
設(shè)置估值器public void setInterpolator(/*Time*/Interpolator value)
設(shè)置插值器public void setTarget(Object target)
設(shè)置目標對象public void setRepeatCount(int value)
設(shè)置動畫重復(fù)次數(shù)public void setRepeatMode(int value)
設(shè)置重復(fù)模式public void setValues(PropertyValuesHolder... values)
設(shè)置值public void setStartDelay(long startDelay)
設(shè)置啟動延時public static void setFrameDelay(long frameDelay)
設(shè)置幀延遲public void setIntValues(int... values)
設(shè)置Int值,對應(yīng)ValueAnimator.ofInt函數(shù)public void setFloatValues(float... values)
設(shè)置Float值。對應(yīng)ValueAnimator.ofFloat函數(shù)public void setCurrentPlayTime(long playTime)
設(shè)置當前執(zhí)行時間public void setObjectValues(Object... values)
設(shè)置Object值,對應(yīng)ValueAnimator.ofObject函數(shù)
上面我們知道ValueAnimator是主要提供一個動態(tài)的變化值,這個值是怎么來變化的,它的變化函數(shù)就是由估值器和插值器來決定的,我們可以自定義估值器和插值器來自定義值的變化,另外這個變化值的類型,ValueAnimator提供了四種類型,Int,F(xiàn)loat,Objcet,PropertyValuesHolder,它囊括了所有的類型。
1、變化值的類型的確定
我們知道,在我們定義一個屬性動畫對象的時候,可以不需要通過自己來創(chuàng)建的,主要有四種方式:
public static ValueAnimator ofInt(int... values) public static ValueAnimator ofFloat(int... values) public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values) public static ValueAnimator ofPropertyValuesHolder(PropertyValuesHolder... values)
從上面我們可以看到,不同的方式其實對應(yīng)的就是不同類型的變化值。第一種方式的變化值類型為Int,第二種方式的變化值類型為Float,第三種方式的變化值類型為Object,第四種方式的變化值類型為PropertyValuesHolder,它其實是一個集合。
2、估值器和插值器
對于給定一個范圍的值,例如上面例子中ValueAnimator.ofFloat(0, 500),它給定的變化范圍為[0, 500],那么在這個范圍內(nèi)到底是如何變化的呢?可以是線性變化,可以是加速變化,可以是減速變化,在內(nèi)部已經(jīng)為我們定義好了幾種變化方式,我們可以根據(jù)情況來進行使用。
首先我們來說說時間插值器和類型估值器
TimeInterpolator中文翻譯為時間插值器,它的作用是根據(jù)時間流逝的百分比來計算出當前屬性值改變的百分比,系統(tǒng)預(yù)置的有LinearInterpolator
(線性插值器:勻速動畫)、AccelerateDecelerateInterpolator
(加速減速插值器:動畫兩頭慢中間快)和DecelerateInterpolator
(減速插值器:動畫越來越慢)等;
下面看看線性插值器的源碼:
public class LinearInterpolator implements Interpolator { public LinearInterpolator() { } public LinearInterpolator(Context context, AttributeSet attrs) { } public float getInterpolation(float input) { return input; } }
我們自定義插值器的時候,只需要重寫getInterpolation方法,其中傳入的input參數(shù)就是時間流逝的百分比,這個百分比就是當前時間的流逝除以設(shè)置的持續(xù)時間Duration來得到的。我們實現(xiàn)這個函數(shù)的時候,可以通過改變這個值來實現(xiàn)我們想要的效果。
TypeEvaluator的中文翻譯為類型估值算法,它的作用是根據(jù)當前屬性改變的百分比來計算改變后的屬性值,系統(tǒng)預(yù)置的有IntEvaluator
(針對整型屬性)、FloatEvaluator
(針對浮點型屬性)和ArgbEvaluator
(針對Color屬性)。
我們知道插值器的作用就是返回當前屬性改變的百分比,這個百分比我們可以通過重寫getInterpolation來自定義。其實真正的變化后的值是從估值器來得到的。
我們來看看IntEvaluator
的源碼:
public class IntEvaluator implements TypeEvaluator<Integer> { public Integer evaluate(float fraction, Integer startValue, Integer endValue) { int startInt = startValue; return (int)(startInt + fraction * (endValue - startInt)); } }
上述算法很簡單,evaluate的三個參數(shù)分別表示:估值小數(shù)、開始值和結(jié)束值,其中的估值小數(shù)就是上面getInterpolation的返回值,開始值就是變化值的開始,結(jié)束值就是變化值的結(jié)束,對應(yīng)上面例子ValueAnimator.ofFloat(0, 500),開始值為0,結(jié)束值為500,通過這三個參數(shù),最終計算出變化后的值,然后將這個值返回去,我們最終得到的就是這個值,然后對指定對象的屬性進行設(shè)置,這樣來實現(xiàn)指定屬性值的變化,從而實現(xiàn)了動畫效果。
所以我們?nèi)绻M远x變化值的變化快慢,我們需要自定義一個插值器和一個估值器,插值器是為估值器服務(wù)的,估值器是為我們服務(wù)的,因為它最終返回了變化后的值。
最后,我們?nèi)绾蔚玫竭@個變化后的值呢?從上面的例子中我們可以看到,我們只需要使用ValueAnimator的addUpdateListener函數(shù)來增加一個更新監(jiān)聽,當這個值變化之后,就會回調(diào)onAnimationUpdate函數(shù),在傳入的參數(shù)ValueAnimator對象中使用getAnimatedValue函數(shù)我們就可以獲取到變化后的那個值,拿到這個變化后的值之后我們就可以動態(tài)的更新對象的屬性值了。
還有需要注意的是,我們?nèi)绻麤]有顯式指定插值器和估值器,它內(nèi)部有默認值。
下面我們來舉個例子;
/** * 拋物線 * @param view */ public void paowuxian(View view) { ValueAnimator valueAnimator = new ValueAnimator(); valueAnimator.setDuration(3000); //這個地方設(shè)置了變化值的類型 valueAnimator.setObjectValues(new PointF(0, 0)); //設(shè)置插值器 valueAnimator.setInterpolator(new LinearInterpolator()); //設(shè)置估值器 valueAnimator.setEvaluator(new TypeEvaluator<PointF>() { // fraction = t / duration @Override public PointF evaluate(float fraction, PointF startValue, PointF endValue) { Log.e(TAG, fraction * 3 + ""); // x方向200px/s ,則y方向0.5 * 10 * t PointF point = new PointF(); point.x = 200 * fraction * 3; point.y = 0.5f * 200 * (fraction * 3) * (fraction * 3); //返回變化值 //這個返回值會在addUpdateListener的回調(diào)中得到 return point; } }); valueAnimator.start(); valueAnimator.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { // 得到估值器里面的那個返回值 PointF point = (PointF) animation.getAnimatedValue(); //設(shè)置屬性值 mBlueBall.setX(point.x); mBlueBall.setY(point.y); } }); }
上面基本說清楚了ValueAnimator的特定和用法,下面來說說如何為這個動畫添加事件監(jiān)聽。
ValueAnimator animator = ValueAnimator.ofFloat(); animator.setFloatValues(0, 500); animator.setTarget(imageView); animator.setDuration(1000); animator.start(); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { imageView.setTranslationY((Float) animation.getAnimatedValue()); } }); animator.addListener(new Animator.AnimatorListener(){ @Override public void onAnimationStart(Animator animation) { Log.d(TAG, "onAnimationStart"); } @Override public void onAnimationEnd(Animator animation) { Log.d(TAG, "onAnimationEnd"); } @Override public void onAnimationCancel(Animator animation) { Log.d(TAG, "onAnimationCancel"); } @Override public void onAnimationRepeat(Animator animation) { Log.d(TAG, "onAnimationRepeat"); } });
從上面可以看到直接添加一個監(jiān)聽就可以了,這樣就可以監(jiān)聽動畫的開始、結(jié)束、被取消、重復(fù)等事件,上面你需要重寫上面四個函數(shù)一個都不能少,如果你只需要重寫自己需要的函數(shù),那你可以使用AnimatorListenerAdapter
,例如只需要重新onAnimationEnd
函數(shù),因為AnimatorListenerAdapter
繼承自AnimatorListener
。
總結(jié)
以上本文關(guān)于Android屬性動畫之ValueAnimator代碼詳解的全部內(nèi)容,希望對大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站其他相關(guān)專題,如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!
相關(guān)文章
Android實現(xiàn)excel/pdf/word/odt/圖片相互轉(zhuǎn)換
這篇文章主要為大家詳細介紹了Android如何實現(xiàn)excel/pdf/word/odt/圖片之間的相互轉(zhuǎn)換,文中的示例代碼講解詳細,感興趣的小伙伴可以了解一下2023-04-04Android 中通過實現(xiàn)線程更新Progressdialog (對話進度條)
這篇文章主要介紹了Android 中通過實現(xiàn)線程更新Progressdialog (對話進度條)的相關(guān)資料,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2016-11-11IDEA打包jar-解決找不到或無法加載主類 main的問題
這篇文章主要介紹了IDEA打包jar-解決找不到或無法加載主類 main的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08RxJava 1升級到RxJava 2過程中踩過的一些“坑”
RxJava2相比RxJava1,它的改動還是很大的,那么下面這篇文章主要給大家總結(jié)了在RxJava 1升級到RxJava 2過程中踩過的一些“坑”,文中介紹的非常詳細,對大家具有一定的參考學(xué)習價值,需要的朋友們下來要一起看看吧。2017-05-05Flutter網(wǎng)絡(luò)請求Dio庫的使用及封裝詳解
本文主要介紹了Flutter網(wǎng)絡(luò)請求Dio庫的使用及封裝詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧2022-04-04Android App中讀取XML與JSON格式數(shù)據(jù)的基本方法示例
這篇文章主要介紹了Android App中讀取XML與JSON格式數(shù)據(jù)的基本方法示例,Android中自帶的JSONObject非常好用,需要的朋友可以參考下2016-03-03