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