Hello,你們好,今天又來裝逼了,裝逼也上癮啊,最近公司不是特別忙,我想這也就是我出來裝逼的最好時機吧!額,,哈哈,進入正題。若有疑問歡迎留言,若有謬誤歡迎批評指正。java
在Tween動畫的討論中,咱們提到在Android中動畫能夠分爲三類:①幀動畫②Tween(補間動畫)③Property Animation(屬性動畫),在前面的文章中,分別對幀動畫和Tween動畫進行了很是詳細的討論,若是有興趣能夠去上面的連接去閱讀。那麼今天就來和你們一塊兒討論下Property Animation,相信經過本系列博客的討論你將對Android中的動畫有個很是詳細的瞭解。
經過本篇博客你將學到如下內容:
①爲何要引入屬性動畫
②屬性動畫的基本用法
③屬性動畫的監聽器
④組合動畫的實現
⑤屬性動畫的XML實現android
首先來看爲何要引入屬性動畫,我相信不少人跟我同樣,看到屬性動畫,在腦海裏閃現的第一個問題就是爲何要引入屬性動畫?咱們都知道Android中已經有幀動畫和補間動畫了,那麼爲何還要引入屬性動畫呢?要想獲得這個問題的正確答案,無疑要去谷歌的官網了,首先咱們來看看官網(官網地址)對Property Animation與補間動畫的區別進行的介紹:app
補間動畫只提供了對View進行增長動畫的能力,因此若是你想對除View以外的其它對象作動畫,你必須實現你本身的代碼來達到這樣的效果。另外,補間動畫只能對View的幾個方面進行動畫的添加,例如View的縮放和旋轉,而不是View的背景顏色等等。框架
補間動畫的另外一個缺點是它只修改了視圖繪製的地方,而不是實際View的自己。好比,你給Button定義了一個在屏幕上移動的動畫,這個Button的繪製是正確的,可是這個Button實際能夠點擊的位置是沒有改變的,因此你必須用你本身的邏輯來解決這個問題。ide
使用屬性動畫這些約束將徹底被解除,而且你能夠對任何對象(Views and non-Views)的任何屬性添加動畫,而且這個對象的自己實際也是改變的。從更高層次上來講,你能夠選擇你想要的屬性,來給其添加動畫,如顏色、位置或大小,而且你能夠經過插值器或者多個動畫的同步,來定義你所須要的動畫。函數
然而補間動畫須要較少的時間來設置,而且也須要更少的代碼。若是補間動畫完成了你所須要作的一切或者現有的代碼就是按照你想要的方式工做的,那麼你沒有必要使用屬性動畫。針對不一樣的狀況有時候也許須要這兩種動畫進行工做纔是有意義的。學習
以上三段就是官網給出的屬性動畫與補間動畫的區別,可能看着比較費勁,其實引入屬性動畫主要有三點緣由:優化
①由於補間動畫只能對View進行操做,而不能對一個對象的屬性,如顏色等進行操做,而屬性動畫能夠,而且屬性動畫的操做範圍不只僅是View,它能夠是任何對象。動畫
②補間動畫只能對View的幾個方面作動畫,也就是說補間動畫不只把範圍縮小到View,並且並非能對View的各個方面作動畫,而只能是alpha(漸變)、scale(縮放)、translate(位移)、rotate(旋轉)這四種動畫。ui
③補間動畫只是改變了View繪製的地方,而並無真正改變View自己。什麼意思?假如手機屏幕上有一個View,咱們讓他作補間動畫向右移動20px,咱們會看到這個View向右移動了20px,而此時你會發現這個View是不能響應你的點擊事件的,只有你點擊原來的位置才能觸發這個View的點擊事件。由於這個View實際還在原來的位置,只不過補間動畫將這個View繪製的地方向右移動了20px,而這個View真正的屬性並無改變。
經過上面的介紹,相信你們已經明白了屬性動畫產生的緣由,瞭解了它產生的背景以後,接下來的一步就是要學習它的用法了。
屬性動畫經常使用的有兩個類分別是ValueAnimator和ObjectAnimator,它的繼承關係圖以下:
從繼承關係圖中咱們能夠清晰的看到ValueAnimator和AnimatorSet是繼承與抽象類Animator的,而ObjectAnimator和TimeAnimator是繼承自ValueAnimator的。這個繼承關係圖,你們要好好識記一下,後面會用到,知道這些關係後,咱們的討論的方向就更加明確了,總共就這麼幾個類,逐一來看看唄。
在學習ValueAnimator的基本使用以前,先來看下它的一些經常使用的方法
在上面的方法中,可能你們比較陌生的就是of開頭的那幾個,其中ofFloat,ofInt它們接收的參數類型都是可變參,因此咱們能夠傳入任何數量的值;傳進去的值列表,就表示動畫時的變化範圍;好比ofInt(3,9,6)就表示從數值3變化到數值9再變化到數值6。而ofObject接收兩個參數一個TypeEvaluator類型的,另外一個是Object類型的可變參數,關於TypeEvaluator,後續的文章會有詳細的討論。而後就是ofPropertyValuesHolder多屬性動畫同時工做管理類,有時候咱們須要對一個對象的多個屬性作動畫,此時就會用到它。setFrameDelay設置多長時間刷新一幀,默認是10ms。但最終依賴系統的當前狀態,通常咱們不用管。
說了這麼多廢話,到底怎麼用,其實ValueAnimator的使用很是簡單,首先來看個最基礎的用法,假如咱們想建立一個值從0到1的動畫,動畫的時長爲200毫秒,代碼應該這樣寫:
執行上面的代碼就執行了一個值從0到1平滑過渡的動畫,從上面的代碼中能夠看出它並無與任何的控件的任何屬性有關係,從它的名字也能看出來它是對值作平滑過渡的,咱們怎麼知道呢?很簡單隻須要對它作監聽就能夠了,咱們只須要添加以下代碼:
在上述代碼中咱們給valueAnimator添加了一個addUpdateListener監聽,在監聽的回調中,回調給咱們的是當前狀態的ValueAnimator 的實例,獲得這個實例後經過調用getAnimatedValue就能夠拿到當前的值,而後將其打印,這裏有一點須要提醒你們注意的是拿到的這個值的類型是與of..後的值得類型相對應的,ofFloat拿到的就是float類型,ofInt拿到的就是int類型。
運行上述代碼打印結果以下:
從打印結果中能夠看到valueAnimator的值在200毫秒內從0逐漸變化到了1,這些中間的過程谷歌已經幫咱們實現好了。
在上面咱們提到ofFloat(float… values)接收的參數類型是可變參,也就是說這裏傳遞的參數的個數是沒有限制,咱們也能夠傳遞多個參數,好比
上述代碼就表示在200毫秒內,valueAnimator的值從0變化到3,而後再變化到1。ofInt的使用與ofFloat相似,只不過傳的值的類型不一樣。
到這裏可能有的同窗會問,說了半天沒有看到ValueAnimator作一個動畫啊,那接下來就讓一個View作位移動畫,代碼以下:
在上述代碼中經過對valueAnimator添加監聽,拿到當前幀的值後,不斷的設置ImageView的TranslatonX(該View在X軸的偏移量)值,從而讓其移動。它的運行效果以下:
能夠看到咱們經過使用ValueAnimator實現了在3秒內在X軸方向上移動100px的效果。這個動畫的操做是在ValueAnimator的監聽中實現的。
小總結: ValueAnimator是計算動畫過程當中變化的值,包含動畫的開始值,結束值,持續時間等屬性。可是這些值與咱們的控件是無關的,要想把計算出來的值應用到對象上,必須爲ValueAnimator註冊一個監聽器,該監聽器負責更新對象的屬性值。在實現這個監聽器的時候,能夠經過getAnimatedValue()的方法來獲取當前動畫的值,拿到這個值後,咱們就能夠隨心所欲了。
相比於ValueAnimator,在開發中可能ObjectAnimator要比ValueAnimator用的多,由於ObjectAnimator能夠直接操做對象的屬性,而不用像ValueAnimator那麼麻煩。
假如讓一個ImageView作旋轉的動畫,代碼能夠這樣寫:
從上述代碼咱們能夠看到ObjectAnimator與ValueAnimator的用法有點類似,又有不一樣,在上述代碼中objectAnimator調用了ofFloat()方法來去建立一個ObjectAnimator的實例,與ValueAnimator不一樣的是,這裏的ofFloat()方法當中接收的參數有點變化了。這裏第一個參數要求傳入一個object對象,即進行動畫的對象,在上面咱們傳了一個ImageView。第二個參數是屬性的名字,由於作旋轉動畫因此這裏傳的屬性的名字爲「rotation」。後面就是可變參數了,這裏咱們傳的是0,360,表示讓ImageView旋轉360度,而後設置時長,調用start方法。美女效果以下,啊,不是,是運行效果以下:
能夠看到美女仍是不錯的,啊。。不是,是運行效果仍是不錯的。
假如想看到透明度漸變的效果呢,代碼能夠這麼寫:
運行效果以下:
在上面的代碼中咱們設置裏的「alpha」屬性,讓其在3秒內完成透明度從0到1的變化。
到這裏從整體上看,屬性動畫的用法仍是比較簡單的,確定有的童鞋會有疑問,ofFloat中的第二個參數都是能傳哪些值呢?上面的代碼中傳了個「alpha」和」rotation」,可是究竟它能傳哪些值呢?這一點從其名字中能夠看出「屬性」動畫,無疑它是操做對象的屬性的,因此它能夠接收任意值,可是這裏有一個前提,那就是這個屬性必需要有get和set方法,什麼意思呢?屬性動畫針對咱們傳入的屬性值,比方說「alpha」,它會去尋找這個屬性名所對應的get和set方法,內部會經過java反射機制來調用set函數修改對象屬性值。由此咱們能夠推斷出ImageView中確定會有對alpha屬性的get和set操做,經過尋找你會發現這兩個方法在ImageView的父類View中,經過尋找在View中確實找到了這兩個方法以下:
這也進一步驗證咱們的說法,到這裏咱們也知道,全部繼承自View的控件均可以進行alpha變換,由於View中就有getAlpha和setAlpha方法。也許到這有的童鞋還會心有餘悸心想上述說的我理解了,可是假如說我想對View的屬性進行變換,不可能每次都要去View的源碼裏去看看它有沒有get和set方法吧,這裏呢,對常常用到的屬性作一個小的總結:
①translationX和translationY:表示在X軸或者Y軸方向上的位移
② scaleX和scaleY:表示在X軸或者Y軸方向上的縮放
③rotation、rotationX和rotationY:這三個屬性控制View對象圍繞支點進行2D和3D旋轉。
④ pivotX和pivotY:這兩個屬性控制着View對象的支點位置,圍繞這個支點進行旋轉和縮放變換處理。默認狀況下,該支點的位置就是View對象的中心點。
⑤x和y:這是兩個簡單實用的屬性,它描述了View對象在它的容器中的最終位置,它是最初的左上角座標和translationX和translationY值的累計和。
⑥ alpha:它表示View對象的alpha透明度。默認值是1(不透明),0表明徹底透明(不可見)。
固然咱們能夠操做的屬性遠遠不止這些,任何屬性只要有get和set方法,咱們均可以操做。
ObjectAnimator是屬性動畫框架中最重要的實行類,建立一個ObjectAnimator只需經過他的靜態工廠類直接返回一個ObjectAnimator對象。傳的參數包括一個對象和對象的屬性名字,但這個屬性必須有get和set函數,還包括屬性的初始值,最終值,還能夠調用setInterpolator設置曲線函數。
對於Animator的監聽在上面的代碼中也略有體現,咱們經過調用addUpdateListener這個方法給ValueAnimator添加了一個監聽,其實從ValueAnimator的源碼中能夠看出它總共是有兩個監聽器的,監聽器相關源碼:
這裏有一點你們須要明白,你們能夠回到開始咱們給出的繼承關係圖,從繼承關係圖中咱們能夠看出
AnimatorSet和ValueAnimator是繼承自Animator的,而ObjectAnimator是繼承自ValueAnimator的。因此對於Animator類中的監聽,AnimatorSet、ValueAnimator、ObjectAnimator均可以用,而ValueAnimator類中的監聽,AnimatorSet中是沒有的,而ObjectAnimator是繼承自ValueAnimator的,因此ValueAnimator和ObjectAnimator都是能夠調用的。理論說完,就上實例咱們能夠這樣爲屬性動畫添加AnimatorListener 監聽:
能夠看到AnimatorListener提供了對動畫開始、動畫重複、動畫結束、取消動畫作了監聽。可是有時候咱們並不須要這麼多啊,好比咱們只想監聽動畫的開始,假如用這種方法須要把這四個方法都重寫才行,代碼太冗餘了,谷歌的攻城獅也是想到了這一點,給咱們提供了一個適配器AnimatorListenerAdapter,有這個類咱們就能夠選擇性的,根據須要添加監聽了,好比咱們只須要添加動畫開始時的監聽,咱們能夠這麼作:
有木有比上面簡化了不少,能夠看出谷歌對屬性動畫的優化仍是下了不少功夫的。
上面咱們都是對一個對象進行單一的動畫,可是一個很酷的動畫每每須要多個動畫協同完成,谷歌也是給我提供了多種實現方式,一塊兒來看看吧。
要想完成多個動畫協同工做須要藉助AnimatorSet這個類,這個類主要提供了三個播放方法,play(),playSequentially(),playTogether()。其中playSequentially()表示多個動畫按順序執,它主要有兩種形式的參數playSequentially(Animator… items)和playSequentially(List <Animator> animator);一個是可變參數,另外一個是動畫集合。
playTogether()表示幾個動畫同時執行,它接收的參數類型與playSequentially()一致。最後就是play方法了,play方法接收一個Animator動畫實例,play(Animator anim),調用它以後會返回一個AnimatorSet.Builder的實例,AnimatorSet.Builder中包括如下四個方法
after(Animator anim) 將現有動畫插入到傳入的動畫以後執行
after(long delay) 將現有動畫延遲指定毫秒後執行
before(Animator anim) 將現有動畫插入到傳入的動畫以前執行
with(Animator anim) 將現有動畫和傳入的動畫同時執行
好了,理論完了以後就要聯繫實際了,那接下來咱們來作一個這樣的組合效果:讓一張圖片旋轉出廠的同時伴隨着漸變和縮放,代碼能夠這樣寫:
運行效果以下
能夠看出它是漸變、旋轉、縮放、三種動畫的組合,效果還算不錯。
接着咱們來看下play的用法,與上述動畫相似,咱們來實現這樣一個動畫,讓一張圖片縮放旋轉出廠,出廠以後讓它消失,能夠用play實現,代碼以下:
運行效果以下:
這樣咱們就用play實現了一個比較不錯的組合動畫了。
前面咱們在學Tween動畫的時候,咱們是分兩篇介紹的,一篇是xml文件配置的實現,一篇是代碼的實現,上述咱們都是用代碼實現的屬性動畫,那麼怎麼配置xml文件實現的?它的實現也很簡單,首先須要作的就是在res下創建一個animator文件夾,而後建立一個xml文件,/res/animator/roation.xml。
在xml文件中總共有能夠用三個標籤,與代碼實現是對應着的
<animator> 對應代碼中的ValueAnimator
<objectAnimator> 對應代碼中的ObjectAnimator
<set< 對應代碼中的AnimatorSet
那麼它們均可以設置哪些屬性值呢?
animator中的屬性以下:
android:duration:表示動畫播放的時長
android:valueFrom:動畫屬性開始的值;取值範圍爲float,int和color,若是未指定,動畫開始屬性經過屬性的get方法得到。顏色用6位16進制數表示(例如:#333333)
android:valueTo:動畫結束值;取值範圍同valueFrom
android:startOffset:取值範圍爲int,動畫的start方法被調用後,延遲多少毫秒執行。
android:repeatCount:動畫重複的次數,能夠設置爲-1或者正整數,-1表示無限循環,假如咱們設置成1,<font color=」#FF000000>表示重複執行一次,因此它總共會執行2次。
android:repeatMode:動畫重複模式,取值爲repeat和reverse;repeat表示正序重播,reverse表示倒序重播,這與前面講的Tween動畫是相似的。
android:valueType:表示參數值類型,取值爲intType和floatType;與android:valueFrom、android:valueTo相對應。若是這裏的取值爲intType,那麼android:valueFrom、android:valueTo的值也就要對應的是int類型的數值。float也是同樣。若是若是android:valueFrom、android:valueTo的值設置爲color類型的值,則不須要設置這個參數;
android:interpolator:設置加速器;
objectAnimator標籤中的屬性以下:
能夠看到與animator中的屬性是差很少的,這裏多了一個
android:propertyName=」string」表示要作動畫的屬性名字。其它的屬性與animator中的一致,就再也不浪費口舌和篇幅了。
set標籤中的屬性以下:
set標籤只有一個屬性以下:
android:ordering=[「together」 | 「sequentially」],其中together表示set標籤下的動畫同時執行,而sequentially表示set標籤下的動畫逐個執行。
理論終於說完了,掌握了理論以後,就能夠來看妹子了。
最後咱們以一個用xml實現的組合動畫結束本篇的內容,咱們實現的效果是這樣的,先讓這個妹子進入到屏幕的正中央,而後讓她旋轉360度,再而後讓她離開屏幕,離開屏幕的同時伴隨着透明度的變化。先看效果:
效果還算比較炫酷吧, 這也算是一個稍微複雜一點的動畫了,與之對應的xml配置內容以下:
怎樣將其xml文件加載到程序中呢?代碼也很簡單,只須要這樣寫:
能夠看到,直接調用AnimatorInflater的loadAnimator將xml文件加載進來,並給其設置目標對象,最後調用start方法啓動,就完成了。xml文件的配置你們能夠根據運行效果本身分析分析。因爲篇幅緣由以及今天是陰天的緣由,這一篇就寫到這裏了,由於我得趕忙去買個避雷針去。