位置: 編程技術(shù) - 正文
推薦整理分享Android屬性動(dòng)畫完全解析(上),初識屬性動(dòng)畫的基本用法(android 屬性動(dòng)畫原理),希望有所幫助,僅作參考,歡迎閱讀內(nèi)容。
文章相關(guān)熱門搜索詞:android的動(dòng)畫類型,Android屬性動(dòng)畫,android 屬性動(dòng)畫上下移動(dòng),android 屬性動(dòng)畫 縮放,android 屬性動(dòng)畫改變view大小,android屬性動(dòng)畫不流暢,android屬性動(dòng)畫平移,Android屬性動(dòng)畫,內(nèi)容如對您有幫助,希望把文章鏈接給更多的朋友!
轉(zhuǎn)載請注明出處: animation)和補(bǔ)間動(dòng)畫(tweened animation)。逐幀動(dòng)畫的工作原理很簡單,其實(shí)就是將一個(gè)完整的動(dòng)畫拆分成一張張單獨(dú)的圖片,然后再將它們連貫起來進(jìn)行播放,類于動(dòng)畫片的工作原理。補(bǔ)間動(dòng)畫則是可以對View進(jìn)行一系列的動(dòng)畫操作,包括淡入淡出、縮放、平移、旋轉(zhuǎn)四種。
然而自Android 3.0版本開始,系統(tǒng)給我們提供了一種全新的動(dòng)畫模式,屬性動(dòng)畫(property animation),它的功能非常強(qiáng)大,彌補(bǔ)了之前補(bǔ)間動(dòng)畫的一些缺陷,幾乎是可以完全替代掉補(bǔ)間動(dòng)畫了。對于逐幀動(dòng)畫和補(bǔ)間動(dòng)畫的用法,我不想再多講,它們的技術(shù)已經(jīng)比較老了,而且網(wǎng)上資料也非常多,那么今天我們這篇文章的主題就是對Android屬性動(dòng)畫進(jìn)行一次完全解析。
為什么要引入屬性動(dòng)畫?Android之前的補(bǔ)間動(dòng)畫機(jī)制其實(shí)還算是比較健全的,在android.view.animation包下面有好多的類可以供我們操作,來完成一系列的動(dòng)畫效果,比如說對View進(jìn)行移動(dòng)、縮放、旋轉(zhuǎn)和淡入淡出,并且我們還可以借助AnimationSet來將這些動(dòng)畫效果組合起來使用,除此之外還可以通過配置Interpolator來控制動(dòng)畫的播放速度等等等等。那么這里大家可能要產(chǎn)生疑問了,既然之前的動(dòng)畫機(jī)制已經(jīng)這么健全了,為什么還要引入屬性動(dòng)畫呢?
其實(shí)上面所謂的健全都是相對的,如果你的需求中只需要對View進(jìn)行移動(dòng)、縮放、旋轉(zhuǎn)和淡入淡出操作,那么補(bǔ)間動(dòng)畫確實(shí)已經(jīng)足夠健全了。但是很顯然,這些功能是不足以覆蓋所有的場景的,一旦我們的需求超出了移動(dòng)、縮放、旋轉(zhuǎn)和淡入淡出這四種對View的操作,那么補(bǔ)間動(dòng)畫就不能再幫我們忙了,也就是說它在功能和可擴(kuò)展方面都有相當(dāng)大的局限性,那么下面我們就來看看補(bǔ)間動(dòng)畫所不能勝任的場景。
注意上面我在介紹補(bǔ)間動(dòng)畫的時(shí)候都有使用“對View進(jìn)行操作”這樣的描述,沒錯(cuò),補(bǔ)間動(dòng)畫是只能夠作用在View上的。也就是說,我們可以對一個(gè)Button、TextView、甚至是LinearLayout、或者其它任何繼承自View的組件進(jìn)行動(dòng)畫操作,但是如果我們想要對一個(gè)非View的對象進(jìn)行動(dòng)畫操作,抱歉,補(bǔ)間動(dòng)畫就幫不上忙了??赡苡械呐笥褧械讲荒芾斫?,我怎么會需要對一個(gè)非View的對象進(jìn)行動(dòng)畫操作呢?這里我舉一個(gè)簡單的例子,比如說我們有一個(gè)自定義的View,在這個(gè)View當(dāng)中有一個(gè)Point對象用于管理坐標(biāo),然后在onDraw()方法當(dāng)中就是根據(jù)這個(gè)Point對象的坐標(biāo)來進(jìn)行繪制的。也就是說,如果我們可以對Point對象進(jìn)行動(dòng)畫操作,那么整個(gè)自定義View的動(dòng)畫效果就有了。顯然,補(bǔ)間動(dòng)畫是不具備這個(gè)功能的,這是它的第一個(gè)缺陷。
然后補(bǔ)間動(dòng)畫還有一個(gè)缺陷,就是它只能夠?qū)崿F(xiàn)移動(dòng)、縮放、旋轉(zhuǎn)和淡入淡出這四種動(dòng)畫操作,那如果我們希望可以對View的背景色進(jìn)行動(dòng)態(tài)地改變呢?很遺憾,我們只能靠自己去實(shí)現(xiàn)了。說白了,之前的補(bǔ)間動(dòng)畫機(jī)制就是使用硬編碼的方式來完成的,功能限定死就是這些,基本上沒有任何擴(kuò)展性可言。
最后,補(bǔ)間動(dòng)畫還有一個(gè)致命的缺陷,就是它只是改變了View的顯示效果而已,而不會真正去改變View的屬性。什么意思呢?比如說,現(xiàn)在屏幕的左上角有一個(gè)按鈕,然后我們通過補(bǔ)間動(dòng)畫將它移動(dòng)到了屏幕的右下角,現(xiàn)在你可以去嘗試點(diǎn)擊一下這個(gè)按鈕,點(diǎn)擊事件是絕對不會觸發(fā)的,因?yàn)閷?shí)際上這個(gè)按鈕還是停留在屏幕的左上角,只不過補(bǔ)間動(dòng)畫將這個(gè)按鈕繪制到了屏幕的右下角而已。
也正是因?yàn)檫@些原因,Android開發(fā)團(tuán)隊(duì)決定在3.0版本當(dāng)中引入屬性動(dòng)畫這個(gè)功能,那么屬性動(dòng)畫是不是就把上述的問題全部解決掉了?下面我們就來一起看一看。
新引入的屬性動(dòng)畫機(jī)制已經(jīng)不再是針對于View來設(shè)計(jì)的了,也不限定于只能實(shí)現(xiàn)移動(dòng)、縮放、旋轉(zhuǎn)和淡入淡出這幾種動(dòng)畫操作,同時(shí)也不再只是一種視覺上的動(dòng)畫效果了。它實(shí)際上是一種不斷地對進(jìn)行操作的機(jī)制,并將賦到指定對象的指定屬性上,可以是任意對象的任意屬性。所以我們?nèi)匀豢梢詫⒁粋€(gè)View進(jìn)行移動(dòng)或者縮放,但同時(shí)也可以對自定義View中的Point對象進(jìn)行動(dòng)畫操作了。我們只需要告訴系統(tǒng)動(dòng)畫的運(yùn)行時(shí)長,需要執(zhí)行哪種類型的動(dòng)畫,以及動(dòng)畫的初始和結(jié)束,剩下的工作就可以全部交給系統(tǒng)去完成了。
既然屬性動(dòng)畫的實(shí)現(xiàn)機(jī)制是通過對目標(biāo)對象進(jìn)行賦并修改其屬性來實(shí)現(xiàn)的,那么之前所說的按鈕顯示的問題也就不復(fù)存在了,如果我們通過屬性動(dòng)畫來移動(dòng)一個(gè)按鈕,那么這個(gè)按鈕就是真正的移動(dòng)了,而不再是僅僅在另外一個(gè)位置繪制了而已。
好了,介紹了這么多,相信大家已經(jīng)對屬性動(dòng)畫有了一個(gè)最基本的認(rèn)識了,下面我們就來開始學(xué)習(xí)一下屬性動(dòng)畫的用法。
ValueAnimatorValueAnimator是整個(gè)屬性動(dòng)畫機(jī)制當(dāng)中最核心的一個(gè)類,前面我們已經(jīng)提到了,屬性動(dòng)畫的運(yùn)行機(jī)制是通過不斷地對進(jìn)行操作來實(shí)現(xiàn)的,而初始和結(jié)束之間的動(dòng)畫過渡就是由ValueAnimator這個(gè)類來負(fù)責(zé)計(jì)算的。它的內(nèi)部使用一種時(shí)間循環(huán)的機(jī)制來計(jì)算與之間的動(dòng)畫過渡,我們只需要將初始和結(jié)束提供給ValueAnimator,并且告訴它動(dòng)畫所需運(yùn)行的時(shí)長,那么ValueAnimator就會自動(dòng)幫我們完成從初始平滑地過渡到結(jié)束這樣的效果。除此之外,ValueAnimator還負(fù)責(zé)管理動(dòng)畫的播放次數(shù)、播放模式、以及對動(dòng)畫設(shè)置監(jiān)聽器等,確實(shí)是一個(gè)非常重要的類。
但是ValueAnimator的用法卻一點(diǎn)都不復(fù)雜,我們先從最簡單的功能看起吧,比如說想要將一個(gè)從0平滑過渡到1,時(shí)長毫秒,就可以這樣寫:
[java] view plaincopyValueAnimator anim = ValueAnimator.ofFloat(0f, 1f); anim.setDuration(); anim.start(); 怎么樣?很簡單吧,調(diào)用ValueAnimator的ofFloat()方法就可以構(gòu)建出一個(gè)ValueAnimator的實(shí)例,ofFloat()方法當(dāng)中允許傳入多個(gè)float類型的參數(shù),這里傳入0和1就表示將從0平滑過渡到1,然后調(diào)用ValueAnimator的setDuration()方法來設(shè)置動(dòng)畫運(yùn)行的時(shí)長,最后調(diào)用start()方法啟動(dòng)動(dòng)畫。用法就是這么簡單,現(xiàn)在如果你運(yùn)行一下上面的代碼,動(dòng)畫就會執(zhí)行了??墒沁@只是一個(gè)將從0過渡到1的動(dòng)畫,又看不到任何界面效果,我們怎樣才能知道這個(gè)動(dòng)畫是不是已經(jīng)真正運(yùn)行了呢?這就需要借助監(jiān)聽器來實(shí)現(xiàn)了,如下所示:
[java] view plaincopyValueAnimator anim = ValueAnimator.ofFloat(0f, 1f); anim.setDuration(); anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float currentValue = (float) animation.getAnimatedValue(); Log.d("TAG", "cuurent value is " currentValue); } }); anim.start(); 可以看到,這里我們通過addUpdateListener()方法來添加一個(gè)動(dòng)畫的監(jiān)聽器,在動(dòng)畫執(zhí)行的過程中會不斷地進(jìn)行回調(diào),我們只需要在回調(diào)方法當(dāng)中將當(dāng)前的取出并打印出來,就可以知道動(dòng)畫有沒有真正運(yùn)行了。運(yùn)行上述代碼,控制臺打印如下所示:從打印日志的我們就可以看出,ValueAnimator確實(shí)已經(jīng)在正常工作了,在毫秒的時(shí)間內(nèi)從0平滑過渡到了1,而這個(gè)計(jì)算工作就是由ValueAnimator幫助我們完成的。另外ofFloat()方法當(dāng)中是可以傳入任意多個(gè)參數(shù)的,因此我們還可以構(gòu)建出更加復(fù)雜的動(dòng)畫邏輯,比如說將一個(gè)在5秒內(nèi)從0過渡到5,再過渡到3,再過渡到,就可以這樣寫:
[java] view plaincopyValueAnimator anim = ValueAnimator.ofFloat(0f, 5f, 3f, f); anim.setDuration(); anim.start(); 當(dāng)然也許你并不需要小數(shù)位數(shù)的動(dòng)畫過渡,可能你只是希望將一個(gè)整數(shù)從0平滑地過渡到,那么也很簡單,只需要調(diào)用ValueAnimator的ofInt()方法就可以了,如下所示:[java] view plaincopyValueAnimator anim = ValueAnimator.ofInt(0, ); ValueAnimator當(dāng)中最常用的應(yīng)該就是ofFloat()和ofInt()這兩個(gè)方法了,另外還有一個(gè)ofObject()方法,我會在下篇文章進(jìn)行講解。那么除此之外,我們還可以調(diào)用setStartDelay()方法來設(shè)置動(dòng)畫延遲播放的時(shí)間,調(diào)用setRepeatCount()和setRepeatMode()方法來設(shè)置動(dòng)畫循環(huán)播放的次數(shù)以及循環(huán)播放的模式,循環(huán)模式包括RESTART和REVERSE兩種,分別表示重新播放和倒序播放的意思。這些方法都很簡單,我就不再進(jìn)行詳細(xì)講解了。
ObjectAnimator相比于ValueAnimator,ObjectAnimator可能才是我們最常接觸到的類,因?yàn)閂alueAnimator只不過是對進(jìn)行了一個(gè)平滑的動(dòng)畫過渡,但我們實(shí)際使用到這種功能的場景好像并不多。而ObjectAnimator則就不同了,它是可以直接對任意對象的任意屬性進(jìn)行動(dòng)畫操作的,比如說View的alpha屬性。
不過雖說ObjectAnimator會更加常用一些,但是它其實(shí)是繼承自ValueAnimator的,底層的動(dòng)畫實(shí)現(xiàn)機(jī)制也是基于ValueAnimator來完成的,因此ValueAnimator仍然是整個(gè)屬性動(dòng)畫當(dāng)中最核心的一個(gè)類。那么既然是繼承關(guān)系,說明ValueAnimator中可以使用的方法在ObjectAnimator中也是可以正常使用的,它們的用法也非常類,這里如果我們想要將一個(gè)TextView在5秒中內(nèi)從常規(guī)變換成全透明,再從全透明變換成常規(guī),就可以這樣寫:
[java] view plaincopyObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f); animator.setDuration(); animator.start(); 可以看到,我們還是調(diào)用了ofFloat()方法來去創(chuàng)建一個(gè)ObjectAnimator的實(shí)例,只不過ofFloat()方法當(dāng)中接收的參數(shù)有點(diǎn)變化了。這里第一個(gè)參數(shù)要求傳入一個(gè)object對象,我們想要對哪個(gè)對象進(jìn)行動(dòng)畫操作就傳入什么,這里我傳入了一個(gè)textview。第二個(gè)參數(shù)是想要對該對象的哪個(gè)屬性進(jìn)行動(dòng)畫操作,由于我們想要改變TextView的不透明度,因此這里傳入"alpha"。后面的參數(shù)就是不固定長度了,想要完成什么樣的動(dòng)畫就傳入什么,這里傳入的就表示將TextView從常規(guī)變換成全透明,再從全透明變換成常規(guī)。之后調(diào)用setDuration()方法來設(shè)置動(dòng)畫的時(shí)長,然后調(diào)用start()方法啟動(dòng)動(dòng)畫,效果如下圖所示:學(xué)會了這一個(gè)用法之后,其它的用法我們就可以舉一反三了,那比如說我們想要將TextView進(jìn)行一次度的旋轉(zhuǎn),就可以這樣寫:
[java] view plaincopyObjectAnimator animator = ObjectAnimator.ofFloat(textview, "rotation", 0f, f); animator.setDuration(); animator.start(); 可以看到,這里我們將第二個(gè)參數(shù)改成了"rotation",然后將動(dòng)畫的初始和結(jié)束分別設(shè)置成0和,現(xiàn)在運(yùn)行一下代碼,效果如下圖所示:那么如果想要將TextView先向左移出屏幕,然后再移動(dòng)回來,就可以這樣寫:
[java] view plaincopyfloat curTranslationX = textview.getTranslationX(); ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "translationX", curTranslationX, -f, curTranslationX); animator.setDuration(); animator.start(); 這里我們先是調(diào)用了TextView的getTranslationX()方法來獲取到當(dāng)前TextView的translationX的位置,然后ofFloat()方法的第二個(gè)參數(shù)傳入"translationX",緊接著后面三個(gè)參數(shù)用于告訴系統(tǒng)TextView應(yīng)該怎么移動(dòng),現(xiàn)在運(yùn)行一下代碼,效果如下圖所示:然后我們還可以TextView進(jìn)行縮放操作,比如說將TextView在垂直方向上放大3倍再還原,就可以這樣寫:
[java] view plaincopyObjectAnimator animator = ObjectAnimator.ofFloat(textview, "scaleY", 1f, 3f, 1f); animator.setDuration(); animator.start(); 這里將ofFloat()方法的第二個(gè)參數(shù)改成了"scaleY",表示在垂直方向上進(jìn)行縮放,現(xiàn)在重新運(yùn)行一下程序,效果如下圖所示:到目前為止,ObjectAnimator的用法還算是相當(dāng)簡單吧,但是我相信肯定會有不少朋友現(xiàn)在心里都有同樣一個(gè)疑問,就是ofFloat()方法的第二個(gè)參數(shù)到底可以傳哪些呢?目前我們使用過了alpha、rotation、translationX和scaleY這幾個(gè),分別可以完成淡入淡出、旋轉(zhuǎn)、水平移動(dòng)、垂直縮放這幾種動(dòng)畫,那么還有哪些是可以使用的呢?其實(shí)這個(gè)問題的答案非常玄乎,就是我們可以傳入任意的到ofFloat()方法的第二個(gè)參數(shù)當(dāng)中。任意的?相信這很出乎大家的意料吧,但事實(shí)就是如此。因?yàn)镺bjectAnimator在設(shè)計(jì)的時(shí)候就沒有針對于View來進(jìn)行設(shè)計(jì),而是針對于任意對象的,它所負(fù)責(zé)的工作就是不斷地向某個(gè)對象中的某個(gè)屬性進(jìn)行賦,然后對象根據(jù)屬性的改變再來決定如何展現(xiàn)出來。
那么比如說我們調(diào)用下面這樣一段代碼:
[java] view plaincopyObjectAnimator.ofFloat(textview, "alpha", 1f, 0f); 其實(shí)這段代碼的意思就是ObjectAnimator會幫我們不斷地改變textview對象中alpha屬性的,從1f變化到0f。然后textview對象需要根據(jù)alpha屬性的改變來不斷刷新界面的顯示,從而讓用戶可以看出淡入淡出的動(dòng)畫效果。那么textview對象中是不是有alpha屬性這個(gè)呢?沒有,不僅textview沒有這個(gè)屬性,連它所有的父類也是沒有這個(gè)屬性的!這就奇怪了,textview當(dāng)中并沒有alpha這個(gè)屬性,ObjectAnimator是如何進(jìn)行操作的呢?其實(shí)ObjectAnimator內(nèi)部的工作機(jī)制并不是直接對我們傳入的屬性名進(jìn)行操作的,而是會去尋找這個(gè)屬性名對應(yīng)的get和set方法,因此alpha屬性所對應(yīng)的get和set方法應(yīng)該就是:
[java] view plaincopypublic void setAlpha(float value); public float getAlpha(); 那么textview對象中是否有這兩個(gè)方法呢?確實(shí)有,并且這兩個(gè)方法是由View對象提供的,也就是說不僅TextView可以使用這個(gè)屬性來進(jìn)行淡入淡出動(dòng)畫操作,任何繼承自View的對象都可以的。既然alpha是這個(gè)樣子,相信大家一定已經(jīng)明白了,前面我們所用的所有屬性都是這個(gè)工作原理,那么View當(dāng)中一定也存在著setRotation()、getRotation()、setTranslationX()、getTranslationX()、setScaleY()、getScaleY()這些方法,不信的話你可以到View當(dāng)中去找一下。
組合動(dòng)畫獨(dú)立的動(dòng)畫能夠?qū)崿F(xiàn)的視覺效果畢竟是相當(dāng)有限的,因此將多個(gè)動(dòng)畫組合到一起播放就顯得尤為重要。幸運(yùn)的是,Android團(tuán)隊(duì)在設(shè)計(jì)屬性動(dòng)畫的時(shí)候也充分考慮到了組合動(dòng)畫的功能,因此提供了一套非常豐富的API來讓我們將多個(gè)動(dòng)畫組合到一起。
實(shí)現(xiàn)組合動(dòng)畫功能主要需要借助AnimatorSet這個(gè)類,這個(gè)類提供了一個(gè)play()方法,如果我們向這個(gè)方法中傳入一個(gè)Animator對象(ValueAnimator或ObjectAnimator)將會返回一個(gè)AnimatorSet.Builder的實(shí)例,AnimatorSet.Builder中包括以下四個(gè)方法:
after(Animator anim) 將現(xiàn)有動(dòng)畫插入到傳入的動(dòng)畫之后執(zhí)行after(long delay) 將現(xiàn)有動(dòng)畫延遲指定毫秒后執(zhí)行before(Animator anim) 將現(xiàn)有動(dòng)畫插入到傳入的動(dòng)畫之前執(zhí)行with(Animator anim) 將現(xiàn)有動(dòng)畫和傳入的動(dòng)畫同時(shí)執(zhí)行好的,有了這四個(gè)方法,我們就可以完成組合動(dòng)畫的邏輯了,那么比如說我們想要讓TextView先從屏幕外移動(dòng)進(jìn)屏幕,然后開始旋轉(zhuǎn)度,旋轉(zhuǎn)的同時(shí)進(jìn)行淡入淡出操作,就可以這樣寫:
[java] view plaincopyObjectAnimator moveIn = ObjectAnimator.ofFloat(textview, "translationX", -f, 0f); ObjectAnimator rotate = ObjectAnimator.ofFloat(textview, "rotation", 0f, f); ObjectAnimator fadeInOut = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f); AnimatorSet animSet = new AnimatorSet(); animSet.play(rotate).with(fadeInOut).after(moveIn); animSet.setDuration(); animSet.start(); 可以看到,這里我們先是把三個(gè)動(dòng)畫的對象全部創(chuàng)建出來,然后new出一個(gè)AnimatorSet對象之后將這三個(gè)動(dòng)畫對象進(jìn)行播放排序,讓旋轉(zhuǎn)和淡入淡出動(dòng)畫同時(shí)進(jìn)行,并把它們插入到了平移動(dòng)畫的后面,最后是設(shè)置動(dòng)畫時(shí)長以及啟動(dòng)動(dòng)畫。運(yùn)行一下上述代碼,效果如下圖所示:Animator監(jiān)聽器在很多時(shí)候,我們希望可以監(jiān)聽到動(dòng)畫的各種事件,比如動(dòng)畫何時(shí)開始,何時(shí)結(jié)束,然后在開始或者結(jié)束的時(shí)候去執(zhí)行一些邏輯處理。這個(gè)功能是完全可以實(shí)現(xiàn)的,Animator類當(dāng)中提供了一個(gè)addListener()方法,這個(gè)方法接收一個(gè)AnimatorListener,我們只需要去實(shí)現(xiàn)這個(gè)AnimatorListener就可以監(jiān)聽動(dòng)畫的各種事件了。
大家已經(jīng)知道,ObjectAnimator是繼承自ValueAnimator的,而ValueAnimator又是繼承自Animator的,因此不管是ValueAnimator還是ObjectAnimator都是可以使用addListener()這個(gè)方法的。另外AnimatorSet也是繼承自Animator的,因此addListener()這個(gè)方法算是個(gè)通用的方法。
添加一個(gè)監(jiān)聽器的代碼如下所示:
[java] view plaincopyanim.addListener(new AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { } @Override public void onAnimationCancel(Animator animation) { } }); 可以看到,我們需要實(shí)現(xiàn)接口中的四個(gè)方法,onAnimationStart()方法會在動(dòng)畫開始的時(shí)候調(diào)用,onAnimationRepeat()方法會在動(dòng)畫重復(fù)執(zhí)行的時(shí)候調(diào)用,onAnimationEnd()方法會在動(dòng)畫結(jié)束的時(shí)候調(diào)用,onAnimationCancel()方法會在動(dòng)畫被取消的時(shí)候調(diào)用。但是也許很多時(shí)候我們并不想要監(jiān)聽那么多個(gè)事件,可能我只想要監(jiān)聽動(dòng)畫結(jié)束這一個(gè)事件,那么每次都要將四個(gè)接口全部實(shí)現(xiàn)一遍就顯得非常繁瑣。沒關(guān)系,為此Android提供了一個(gè)適配器類,叫作AnimatorListenerAdapter,使用這個(gè)類就可以解決掉實(shí)現(xiàn)接口繁瑣的問題了,如下所示:
[java] view plaincopyanim.addListener(new AnimatorListenerAdapter() { }); 這里我們向addListener()方法中傳入這個(gè)適配器對象,由于AnimatorListenerAdapter中已經(jīng)將每個(gè)接口都實(shí)現(xiàn)好了,所以這里不用實(shí)現(xiàn)任何一個(gè)方法也不會報(bào)錯(cuò)。那么如果我想監(jiān)聽動(dòng)畫結(jié)束這個(gè)事件,就只需要單獨(dú)重寫這一個(gè)方法就可以了,如下所示:[java] view plaincopyanim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { } }); 使用XML編寫動(dòng)畫我們可以使用代碼來編寫所有的動(dòng)畫功能,這也是最常用的一種做法。不過,過去的補(bǔ)間動(dòng)畫除了使用代碼編寫之外也是可以使用XML編寫的,因此屬性動(dòng)畫也提供了這一功能,即通過XML來完成和代碼一樣的屬性動(dòng)畫功能。
通過XML來編寫動(dòng)畫可能會比通過代碼來編寫動(dòng)畫要慢一些,但是在重用方面將會變得非常輕松,比如某個(gè)將通用的動(dòng)畫編寫到XML里面,我們就可以在各個(gè)界面當(dāng)中輕松去重用它。
如果想要使用XML來編寫動(dòng)畫,首先要在res目錄下面新建一個(gè)animator文件夾,所有屬性動(dòng)畫的XML文件都應(yīng)該存放在這個(gè)文件夾當(dāng)中。然后在XML文件中我們一共可以使用如下三種標(biāo)簽:
<animator> 對應(yīng)代碼中的ValueAnimator<objectAnimator> 對應(yīng)代碼中的ObjectAnimator<set> 對應(yīng)代碼中的AnimatorSet那么比如說我們想要實(shí)現(xiàn)一個(gè)從0到平滑過渡的動(dòng)畫,在XML當(dāng)中就可以這樣寫:
[html] view plaincopy<animator xmlns:android=" android:valueFrom="0" android:valueTo="" android:valueType="intType"/> 而如果我們想將一個(gè)視圖的alpha屬性從1變成0,就可以這樣寫:[html] view plaincopy<objectAnimator xmlns:android=" android:valueFrom="1" android:valueTo="0" android:valueType="floatType" android:propertyName="alpha"/> 其實(shí)XML編寫動(dòng)畫在可讀性方面還是挺高的,上面的內(nèi)容相信不用我做解釋大家也都看得懂吧。另外,我們也可以使用XML來完成復(fù)雜的組合動(dòng)畫操作,比如將一個(gè)視圖先從屏幕外移動(dòng)進(jìn)屏幕,然后開始旋轉(zhuǎn)度,旋轉(zhuǎn)的同時(shí)進(jìn)行淡入淡出操作,就可以這樣寫:
[html] view plaincopy<set xmlns:android=" android:ordering="sequentially" > <objectAnimator android:duration="" android:propertyName="translationX" android:valueFrom="-" android:valueTo="0" android:valueType="floatType" > </objectAnimator> <set android:ordering="together" > <objectAnimator android:duration="" android:propertyName="rotation" android:valueFrom="0" android:valueTo="" android:valueType="floatType" > </objectAnimator> <set android:ordering="sequentially" > <objectAnimator android:duration="" android:propertyName="alpha" android:valueFrom="1" android:valueTo="0" android:valueType="floatType" > </objectAnimator> <objectAnimator android:duration="" android:propertyName="alpha" android:valueFrom="0" android:valueTo="1" android:valueType="floatType" > </objectAnimator> </set> </set> </set> 這段XML實(shí)現(xiàn)的效果和我們剛才通過代碼來實(shí)現(xiàn)的組合動(dòng)畫的效果是一模一樣的,每個(gè)參數(shù)的含義都非常清楚,相信大家都是一看就懂,我就不再一一解釋了。最后XML文件是編寫好了,那么我們?nèi)绾卧诖a中把文件加載進(jìn)來并將動(dòng)畫啟動(dòng)呢?只需調(diào)用如下代碼即可:
[java] view plaincopyAnimator animator = AnimatorInflater.loadAnimator(context, R.animator.anim_file); animator.setTarget(view); animator.start(); 調(diào)用AnimatorInflater的loadAnimator來將XML動(dòng)畫文件加載進(jìn)來,然后再調(diào)用setTarget()方法將這個(gè)動(dòng)畫設(shè)置到某一個(gè)對象上面,最后再調(diào)用start()方法啟動(dòng)動(dòng)畫就可以了,就是這么簡單。好的,通過本篇文章的學(xué)習(xí),我相信大家已經(jīng)對屬性動(dòng)畫的基本用法已經(jīng)有了一個(gè)相當(dāng)不錯(cuò)的認(rèn)識,并把最常用的一些功能都掌握好了,那么本篇文章的內(nèi)容就到這里,下篇文章當(dāng)中會繼續(xù)介紹屬性動(dòng)畫,講解ValueAnimator和ObjectAnimator的高級用法,感興趣的朋友請繼續(xù)閱讀 Android屬性動(dòng)畫完全解析(中),ValueAnimator和ObjectAnimator的高級用法 。
開源項(xiàng)目源碼解析-xUtils 源碼解析 xUtils源碼解析本文為Android開源項(xiàng)目源碼解析中xUtils部分。項(xiàng)目地址:xUtils,分析的版本:c2ac,Demo地址:xUtilsDemo分析者:Caij,校對者:maogy,校對
掌握Activity 的生命周期(Lifecycle) Activity的生命周期(Lifecycle)在用戶與App進(jìn)行交互,開啟APP,退出APP,按Home鍵回到桌面等等的時(shí)候,相關(guān)的Activity實(shí)例將會不斷的切換Activity生命周期中
android開發(fā)之單點(diǎn)觸摸 相對于多點(diǎn)觸摸,單點(diǎn)觸摸還是很簡單的。新建一個(gè)工程,先看看布局文件:RelativeLayoutxmlns:android="
標(biāo)簽: android 屬性動(dòng)畫原理
本文鏈接地址:http://esstyw.cn/biancheng/382242.html 轉(zhuǎn)載請保留說明!網(wǎng)站地圖: 企業(yè)信息 工商信息 財(cái)稅知識 網(wǎng)絡(luò)常識 編程技術(shù)
友情鏈接: 武漢網(wǎng)站建設(shè)