Android 之Animator屬性動畫講解【上】

android?Animator 講解【上】

目錄

1.簡介
2.屬性動畫相對補間動畫和幀動畫好處
3.ValueAnimator 屬性動畫
4.ObjectAnimator 屬性動畫
5.AnimatorSet組合動畫
6.使用XML編寫動畫
7.動畫監聽器

簡介

使用安卓手機的朋友的都知道,手機上面有一些效果比較炫酷。因為系統在一開始的時候就給我們提供了兩種實現動畫效果的方式:
? 逐幀動畫(frame-by-frame animation)
? 補間動畫(tweened animation)

逐幀動畫的理解比較簡單,其實就是把一個完整的動畫拆分成一張張圖片,然后再把他們串聯起來進行播放,有點像看視頻一樣

補間動畫是可以進行對View進行一系列的動畫操作,包括淡入淡出、縮放、平移、旋轉4種效果。

在Android3.0之后官方給出一種全新的動畫模式,屬性動畫(property animation),它的功能非常強大,彌補了之前補間動畫的一些缺陷,幾乎是可以完全替代掉補間動畫了。

屬性動畫相對補間動畫和幀動畫好處

Android之前推存的補間動畫是相對于View來就行操作的,比如說對view進行移動、縮放、旋轉、淡入淡出等常見效果。但是如果我們的需求超出這寫操作,那么補間動畫就不能滿足我們了。補間動畫的擴展性能是有相當大的局限性的,既然補間動畫不能勝任需求。那么我們就該換另一種更有滿足我們擴展性能更好的動畫了。

屬性動畫

為什么屬性動畫能勝任我們的需求呢?
相對補間動畫的效果,比如我對這個view 就行點擊事件監聽,原位置是(10,10),但是我在該為進行了補間動畫的移動一個位置(100,100),當我們去點事該vew的時候,事件不會被觸發,點擊原來的位置(10,10)事件被觸發了。
為什么會這樣?
因為補間動畫只是改變了view的顯示效果,但是并沒有改變該view位置狀態,view控件依然在位置(10,10)中。

Android3.0推存出來的屬性動畫,不僅能夠實現補間動畫的效果,還能填補補間動畫的不足。屬性動畫是相對于屬性來改變View的,所以上面的移動到(100,100)位置,view的 X和Y屬性自然也是100了,所以當你點擊該vewi的時候,事件在位置(100,100)觸發了,在位置(10,10)沒有被觸發!

ValueAnimator 屬性動畫

ValueAnimator是整個屬性動畫機制當中最核心的一個類,前面我們已經提到了,屬性動畫的運行機制是通過不斷地對值進行操作來實現的,而初始值和結束值之間的動畫過渡就是由ValueAnimator這個類來負責計算的。它的內部使用一種時間循環的機制來計算值與值之間的動畫過渡,我們只需要將初始值和結束值提供給ValueAnimator,并且告訴它動畫所需運行的時長,那么ValueAnimator就會自動幫我們完成從初始值平滑地過渡到結束值這樣的效果。除此之外,ValueAnimator還負責管理動畫的播放次數、播放模式、以及對動畫設置監聽器等,確實是一個非常重要的類。

還有ValueAnimator的用法卻一點都不復雜,我們先從最簡單的功能看起吧,比如說想要將一個值從0平滑過渡到1,時長100毫秒,就可以這樣寫:

ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
anim.setDuration(100);
anim.start();

很簡單的代碼就可以構建出一個屬性動畫實例。設置的動畫是100我們來看一下ofFloat源碼

public static ValueAnimator ofFloat(float... values) {ValueAnimator anim =new ValueAnimator();? ? anim.setFloatValues(values);? ? return anim;}

可以看出,這里的ofFloat方法里面可以傳入很多個float,是以數組的形式的一個參數。如下代碼:

ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
anim.setDuration(300);
// 監聽變化狀態
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) {
// 打印 log?animation.getAnimatedValue() ?
?}});
setAnimatorListener(anim, "沒有添加控件狀態下測試ofInt");

anim.start();

如圖所示:

從打印的值中,我們可以看出數值是從0到1變大的,而且增加不是均勻的。當然我們也可以設置均勻的增加,不過這個知識點劉下一章在講解。

在ValueAnimator中,我們還可以調用setStartDelay()方法來設置動畫延遲播放的時間,調用setRepeatCount()和setRepeatMode()方法來設置動畫循環播放的次數以及循環播放的模式,循環模式包括RESTART和REVERSE兩種,分別表示重新播放和倒序播放的意思。需要連接的可以百度一下,因為這已經是很成熟的技術了。


ObjectAnimator屬性動畫

ObjectAnimator 是?ValueAnimator的子類,也是我們在開發中接觸最多的一個類。既然是ValueAnimator的子類,那么ValueAnimator可以用的方法ObjectAnimator 當然也可以用了,ObjectAnimator 也是很好用的。比如想把一個TextView做淡入淡出的效果,效果是這樣子的:不透明 》全透明》不透明》半透明》透明》不透明

ObjectAnimator anim = ObjectAnimator
? ? ? ? ? ? .ofFloat(textView, "alpha", 1f, 0f, 1f, 0.5f, 0f, 1f);
anim.setDuration(3000);
anim.start();

效果如下:

第一個參數是 給定的控件 View ,第二個參數可能很多人不理解,其實這個參數是可以隨意起的,就是你可以隨意傳任何對象,他所負責的工作就是不斷的向你起的這個屬性對象進行賦值,然后根據屬性值的改變在如何展示出來的。

就拿剛剛的這個來說

ObjectAnimator.ofFloat(textView, "alpha", 1f, 0f, 1f, 0.5f, 0f, 1f);

textView是沒有存在這個?alpha 屬性的,它的父類View也是一樣沒有這個?alpha 屬性。是不是奇怪,很有屬性怎么又變成了是屬性對象?別急,慢慢跟大家分析,其實這個?alpha 屬性不是根據View中有沒有這個屬性的,而是根據 view中是否存在?alpha 的set和get方法的,我們設置的動畫也是一樣哦,設置?alpha 就是為了去 view中尋找?alpha對應的?setAlpha 和?getAlpha 方法。不信的同學可以在 View中進行查詢哦。

第三個參數就不用多說了吧 ,上面有提到他是一個數組形式的參數,可以傳多個對應的類型執行動畫效果。

根據上面的第二個參數是可以在View中獲取set、get方法的,那么如果第二個參數是:rotation、translationX、translationY、scaleX、scaleY也是一樣可以在View中找到他們的set和get方法的。說了那么多,為什么這個參數是這樣子的,可以自己命名嗎? 答案是肯定的,這個參數也可以自定義自己的一個屬性名字,上面提到過,而剛剛說的那些?alpha、rotation、translationX、translationY、scaleX、scaleY 都是系統View中自帶的set、get方法,也是一樣沒有這個屬性名,只有對應的方法名。

如果我們要想自己定義屬性,下一章我們在重點學習。

AnimatorSet組合動畫

什么是組合動畫呢?

組合動畫就是能實現將多個動畫組合到一起播放!

實現組合動畫功能主要需要借助AnimatorSet這個類,這個類提供了一個play()方法,如果我們向這個方法中傳入一個Animator對象(ValueAnimator或ObjectAnimator)將會返回一個AnimatorSet.Builder的實例,AnimatorSet.Builder中包括以下四個方法:

? ? after(Animator anim) ? 將現有動畫插入到傳入的動畫之后執行
? ? after(long delay) ? 將現有動畫延遲指定毫秒后執行
? ? before(Animator anim) ? 將現有動畫插入到傳入的動畫之前執行
? ? with(Animator anim) ? 將現有動畫和傳入的動畫同時執行

看一下幾個方法實現的效果:

ObjectAnimator anim1 = ObjectAnimator
? ? ? ? .ofFloat(mTest, "translationX", 0f, 400f, -50f, 270f, -150f, 100f, 0f);

ObjectAnimator anim2 = ObjectAnimator
? ? ? ? .ofFloat(mTest, "translationY", 0f, 400f, -50f, 270f, -150f, 100f, 0f);

ObjectAnimator anim3 = ObjectAnimator
? ? ? ? .ofFloat(mTest, "rotation", 0f, 360f, -180f, 270f, 0f);

ObjectAnimator anim4 = ObjectAnimator
? ? ? ?? .ofFloat(mTest, "scaleX", 1f, 3f, 2f, 1f);

AnimatorSet animSet =new AnimatorSet();
animSet.play(anim1).with(anim2).after(anim3).before(anim4);
animSet.setDuration(5000);
animSet.start();

動畫執行順序:anim3 》anim2+anim1》anim4


組合動畫1

ObjectAnimator anim1 = ObjectAnimator
? ? ? ? ? .ofFloat(mTest, "translationX", 0f, 400f, -50f, 270f, -150f, 100f, 0f);

ObjectAnimator anim2 = ObjectAnimator
? ? ? ?? .ofFloat(mTest, "translationY", 0f, 400f, -50f, 270f, -150f, 100f, 0f);

ObjectAnimator anim3 = ObjectAnimator
? ? ? ?? .ofFloat(mTest, "rotation", 0f, 360f, -180f, 270f, 0f);

AnimatorSet animSet =new AnimatorSet();
animSet.play(anim1).with(anim2).with(anim3);
animSet.setDuration(5000);
animSet.start();

動畫執行順序:anim1+anim2+anim3 同時執行


組合動畫2


使用XML編寫動畫

除了代碼編寫動畫,其實我們也可以在XML中編寫動畫。首先我們需要在res中新建一個文件夾?animator 來存儲我們編寫的動畫。

在XML中,我們有三種標簽是可以用來編寫動畫的:

??< animator > 對應代碼中的ValueAnimator

?< objectAnimator?> 對應代碼中的ObjectAnimator

??< set > 對應代碼中的AnimatorSet

好了,我們來實現一個從0到300平滑過渡的動畫,在XML當中就可以這樣寫:

<animator?xmlns:android="http://schemas.android.com/apk/res/android" ?
android:valueFrom="0" ?
android:valueTo="300" ?
android:valueType="intType" />

想將一個視圖的alpha屬性2秒內從1變成0,就可以這樣寫:

<objectAnimator?xmlns:android="http://schemas.android.com/apk/res/android" ?
android:duration="2000" ?
android:valueFrom="1" ?
android:valueTo="0" ?
android:valueType="floatType" ?
android:propertyName="alpha" />

用 set 標簽組合上面的動畫就可以這樣子寫:

< set?xmlns:android="http://schemas.android.com/apk/res/android"
?android:ordering="sequentially"?> ?

< objectAnimator ?
? ? ?android:duration="2000" ?
? ? ?android:propertyName="alpha" ?
? ? ?android:valueFrom="1" ?
? ? ?android:valueTo="0" ?
? ? ?android:valueType="floatType" ?/ > ?

< objectAnimator ?
? ? ?android:duration="2000" ?
? ? ?android:valueFrom="0" ?
? ? ?android:valueTo="300" ?
? ? ?android:propertyName="translationX?"
? ? ?android:valueType="intType" / > ?

</set>


動畫監聽器

動畫監聽器是可以隨時隨地的監聽當前動畫執行變化狀態的。監聽器的功能:監聽動畫開始前,動畫結束,動畫當前執行的狀態都可以獲取。Animator類當中就是提供了一個addListener()方法來實現這寫效果的,這個方法接收一個AnimatorListener,我們只需要去實現這個AnimatorListener就可以監聽動畫的各種事件了。

該監聽器實現AnimatorListener接口有四個方法:

anim.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)?{ ?
? ? } ?
}); ?

onAnimationStart:動畫開始的時候調用
onAnimationRepeat()方法會在動畫重復執行的時候調用
onAnimationEnd()方法會在動畫結束的時候調用
onAnimationCancel()方法會在動畫被取消的時候調用。

有時候我們沒有必要實現那么事件方法,只需要四個方法中的某一個,這時候Android提供了一個適配器類,叫作AnimatorListenerAdapter,使用這個類就可以解決掉實現接口繁瑣的問題了,如下所示:

anim.addListener(new?AnimatorListenerAdapter()?{ ?
});?

這里我們向addListener()方法中傳入這個適配器對象,由于AnimatorListenerAdapter中已經將每個接口都實現好了,所以這里不用實現任何一個方法也不會報錯。那么如果我想監聽動畫結束這個事件,就只需要單獨重寫這一個方法就可以了,如下所示:

anim.addListener(new?AnimatorListenerAdapter()?{ ?
@Override ?
public?void?onAnimationEnd(Animator?animation)?{ ?
? ? } ?
});?


源碼


好了,本篇就在此完結了,下篇文章我們重點解析屬性動畫的類型和插值器

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容