Android 之Animator屬性動(dòng)畫講解【上】

android?Animator 講解【上】

目錄

1.簡(jiǎn)介
2.屬性動(dòng)畫相對(duì)補(bǔ)間動(dòng)畫和幀動(dòng)畫好處
3.ValueAnimator 屬性動(dòng)畫
4.ObjectAnimator 屬性動(dòng)畫
5.AnimatorSet組合動(dòng)畫
6.使用XML編寫動(dòng)畫
7.動(dòng)畫監(jiān)聽器

簡(jiǎn)介

使用安卓手機(jī)的朋友的都知道碉渡,手機(jī)上面有一些效果比較炫酷娃豹。因?yàn)橄到y(tǒng)在一開始的時(shí)候就給我們提供了兩種實(shí)現(xiàn)動(dòng)畫效果的方式:
? 逐幀動(dòng)畫(frame-by-frame animation)
? 補(bǔ)間動(dòng)畫(tweened animation)

逐幀動(dòng)畫的理解比較簡(jiǎn)單绳泉,其實(shí)就是把一個(gè)完整的動(dòng)畫拆分成一張張圖片,然后再把他們串聯(lián)起來進(jìn)行播放,有點(diǎn)像看視頻一樣

補(bǔ)間動(dòng)畫是可以進(jìn)行對(duì)View進(jìn)行一系列的動(dòng)畫操作,包括淡入淡出、縮放瞻离、平移、旋轉(zhuǎn)4種效果乒裆。

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

屬性動(dòng)畫相對(duì)補(bǔ)間動(dòng)畫和幀動(dòng)畫好處

Android之前推存的補(bǔ)間動(dòng)畫是相對(duì)于View來就行操作的稿黄,比如說對(duì)view進(jìn)行移動(dòng)喊衫、縮放、旋轉(zhuǎn)杆怕、淡入淡出等常見效果族购。但是如果我們的需求超出這寫操作,那么補(bǔ)間動(dòng)畫就不能滿足我們了陵珍。補(bǔ)間動(dòng)畫的擴(kuò)展性能是有相當(dāng)大的局限性的寝杖,既然補(bǔ)間動(dòng)畫不能勝任需求。那么我們就該換另一種更有滿足我們擴(kuò)展性能更好的動(dòng)畫了互纯。

屬性動(dòng)畫

為什么屬性動(dòng)畫能勝任我們的需求呢瑟幕?
相對(duì)補(bǔ)間動(dòng)畫的效果,比如我對(duì)這個(gè)view 就行點(diǎn)擊事件監(jiān)聽留潦,原位置是(10,10)只盹,但是我在該為進(jìn)行了補(bǔ)間動(dòng)畫的移動(dòng)一個(gè)位置(100,100),當(dāng)我們?nèi)c(diǎn)事該vew的時(shí)候兔院,事件不會(huì)被觸發(fā)殖卑,點(diǎn)擊原來的位置(10,10)事件被觸發(fā)了。
為什么會(huì)這樣坊萝?
因?yàn)檠a(bǔ)間動(dòng)畫只是改變了view的顯示效果孵稽,但是并沒有改變?cè)搗iew位置狀態(tài),view控件依然在位置(10屹堰,10)中肛冶。

Android3.0推存出來的屬性動(dòng)畫,不僅能夠?qū)崿F(xiàn)補(bǔ)間動(dòng)畫的效果扯键,還能填補(bǔ)補(bǔ)間動(dòng)畫的不足睦袖。屬性動(dòng)畫是相對(duì)于屬性來改變View的,所以上面的移動(dòng)到(100荣刑,100)位置馅笙,view的 X和Y屬性自然也是100了,所以當(dāng)你點(diǎn)擊該vewi的時(shí)候厉亏,事件在位置(100董习,100)觸發(fā)了,在位置(10爱只,10)沒有被觸發(fā)皿淋!

ValueAnimator 屬性動(dòng)畫

ValueAnimator是整個(gè)屬性動(dòng)畫機(jī)制當(dāng)中最核心的一個(gè)類,前面我們已經(jīng)提到了,屬性動(dòng)畫的運(yùn)行機(jī)制是通過不斷地對(duì)值進(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í)長(zhǎng)妇拯,那么ValueAnimator就會(huì)自動(dòng)幫我們完成從初始值平滑地過渡到結(jié)束值這樣的效果。除此之外洗鸵,ValueAnimator還負(fù)責(zé)管理動(dòng)畫的播放次數(shù)越锈、播放模式、以及對(duì)動(dòng)畫設(shè)置監(jiān)聽器等膘滨,確實(shí)是一個(gè)非常重要的類甘凭。

還有ValueAnimator的用法卻一點(diǎn)都不復(fù)雜,我們先從最簡(jiǎn)單的功能看起吧吏祸,比如說想要將一個(gè)值從0平滑過渡到1对蒲,時(shí)長(zhǎng)100毫秒,就可以這樣寫:

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

很簡(jiǎn)單的代碼就可以構(gòu)建出一個(gè)屬性動(dòng)畫實(shí)例贡翘。設(shè)置的動(dòng)畫是100我們來看一下ofFloat源碼

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

可以看出蹈矮,這里的ofFloat方法里面可以傳入很多個(gè)float,是以數(shù)組的形式的一個(gè)參數(shù)鸣驱。如下代碼:

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

anim.start();

如圖所示:

從打印的值中泛鸟,我們可以看出數(shù)值是從0到1變大的,而且增加不是均勻的踊东。當(dāng)然我們也可以設(shè)置均勻的增加北滥,不過這個(gè)知識(shí)點(diǎn)劉下一章在講解。

在ValueAnimator中闸翅,我們還可以調(diào)用setStartDelay()方法來設(shè)置動(dòng)畫延遲播放的時(shí)間再芋,調(diào)用setRepeatCount()和setRepeatMode()方法來設(shè)置動(dòng)畫循環(huán)播放的次數(shù)以及循環(huán)播放的模式,循環(huán)模式包括RESTART和REVERSE兩種坚冀,分別表示重新播放和倒序播放的意思济赎。需要連接的可以百度一下,因?yàn)檫@已經(jīng)是很成熟的技術(shù)了记某。


ObjectAnimator屬性動(dòng)畫

ObjectAnimator 是?ValueAnimator的子類司训,也是我們?cè)陂_發(fā)中接觸最多的一個(gè)類。既然是ValueAnimator的子類液南,那么ValueAnimator可以用的方法ObjectAnimator 當(dāng)然也可以用了壳猜,ObjectAnimator 也是很好用的。比如想把一個(gè)TextView做淡入淡出的效果滑凉,效果是這樣子的:不透明 》全透明》不透明》半透明》透明》不透明

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

效果如下:

第一個(gè)參數(shù)是 給定的控件 View 统扳,第二個(gè)參數(shù)可能很多人不理解喘帚,其實(shí)這個(gè)參數(shù)是可以隨意起的,就是你可以隨意傳任何對(duì)象闪幽,他所負(fù)責(zé)的工作就是不斷的向你起的這個(gè)屬性對(duì)象進(jìn)行賦值啥辨,然后根據(jù)屬性值的改變?cè)谌绾握故境鰜淼摹?/p>

就拿剛剛的這個(gè)來說

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

textView是沒有存在這個(gè)?alpha 屬性的,它的父類View也是一樣沒有這個(gè)?alpha 屬性盯腌。是不是奇怪,很有屬性怎么又變成了是屬性對(duì)象陨瘩?別急腕够,慢慢跟大家分析,其實(shí)這個(gè)?alpha 屬性不是根據(jù)View中有沒有這個(gè)屬性的舌劳,而是根據(jù) view中是否存在?alpha 的set和get方法的帚湘,我們?cè)O(shè)置的動(dòng)畫也是一樣哦,設(shè)置?alpha 就是為了去 view中尋找?alpha對(duì)應(yīng)的?setAlpha 和?getAlpha 方法甚淡。不信的同學(xué)可以在 View中進(jìn)行查詢哦大诸。

第三個(gè)參數(shù)就不用多說了吧 ,上面有提到他是一個(gè)數(shù)組形式的參數(shù)贯卦,可以傳多個(gè)對(duì)應(yīng)的類型執(zhí)行動(dòng)畫效果资柔。

根據(jù)上面的第二個(gè)參數(shù)是可以在View中獲取set、get方法的撵割,那么如果第二個(gè)參數(shù)是:rotation贿堰、translationX、translationY啡彬、scaleX羹与、scaleY也是一樣可以在View中找到他們的set和get方法的。說了那么多庶灿,為什么這個(gè)參數(shù)是這樣子的纵搁,可以自己命名嗎? 答案是肯定的往踢,這個(gè)參數(shù)也可以自定義自己的一個(gè)屬性名字腾誉,上面提到過,而剛剛說的那些?alpha菲语、rotation妄辩、translationX、translationY山上、scaleX眼耀、scaleY 都是系統(tǒng)View中自帶的set、get方法佩憾,也是一樣沒有這個(gè)屬性名哮伟,只有對(duì)應(yīng)的方法名干花。

如果我們要想自己定義屬性,下一章我們?cè)谥攸c(diǎn)學(xué)習(xí)楞黄。

AnimatorSet組合動(dòng)畫

什么是組合動(dòng)畫呢池凄?

組合動(dòng)畫就是能實(shí)現(xiàn)將多個(gè)動(dòng)畫組合到一起播放!

實(shí)現(xiàn)組合動(dòng)畫功能主要需要借助AnimatorSet這個(gè)類鬼廓,這個(gè)類提供了一個(gè)play()方法肿仑,如果我們向這個(gè)方法中傳入一個(gè)Animator對(duì)象(ValueAnimator或ObjectAnimator)將會(huì)返回一個(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è)方法實(shí)現(xiàn)的效果:

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();

動(dòng)畫執(zhí)行順序:anim3 》anim2+anim1》anim4


組合動(dòng)畫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();

動(dòng)畫執(zhí)行順序:anim1+anim2+anim3 同時(shí)執(zhí)行


組合動(dòng)畫2


使用XML編寫動(dòng)畫

除了代碼編寫動(dòng)畫碎税,其實(shí)我們也可以在XML中編寫動(dòng)畫尤慰。首先我們需要在res中新建一個(gè)文件夾?animator 來存儲(chǔ)我們編寫的動(dòng)畫。

在XML中雷蹂,我們有三種標(biāo)簽是可以用來編寫動(dòng)畫的:

??< animator > 對(duì)應(yīng)代碼中的ValueAnimator

?< objectAnimator?> 對(duì)應(yīng)代碼中的ObjectAnimator

??< set > 對(duì)應(yīng)代碼中的AnimatorSet

好了伟端,我們來實(shí)現(xiàn)一個(gè)從0到300平滑過渡的動(dòng)畫,在XML當(dāng)中就可以這樣寫:

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

想將一個(gè)視圖的alpha屬性2秒內(nèi)從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 標(biāo)簽組合上面的動(dòng)畫就可以這樣子寫:

< 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>


動(dòng)畫監(jiān)聽器

動(dòng)畫監(jiān)聽器是可以隨時(shí)隨地的監(jiān)聽當(dāng)前動(dòng)畫執(zhí)行變化狀態(tài)的责蝠。監(jiān)聽器的功能:監(jiān)聽動(dòng)畫開始前,動(dòng)畫結(jié)束萎庭,動(dòng)畫當(dāng)前執(zhí)行的狀態(tài)都可以獲取霜医。Animator類當(dāng)中就是提供了一個(gè)addListener()方法來實(shí)現(xiàn)這寫效果的,這個(gè)方法接收一個(gè)AnimatorListener擎椰,我們只需要去實(shí)現(xiàn)這個(gè)AnimatorListener就可以監(jiān)聽動(dòng)畫的各種事件了支子。

該監(jiān)聽器實(shí)現(xiàn)AnimatorListener接口有四個(gè)方法:

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:動(dòng)畫開始的時(shí)候調(diào)用
onAnimationRepeat()方法會(huì)在動(dòng)畫重復(fù)執(zhí)行的時(shí)候調(diào)用
onAnimationEnd()方法會(huì)在動(dòng)畫結(jié)束的時(shí)候調(diào)用
onAnimationCancel()方法會(huì)在動(dòng)畫被取消的時(shí)候調(diào)用。

有時(shí)候我們沒有必要實(shí)現(xiàn)那么事件方法达舒,只需要四個(gè)方法中的某一個(gè)值朋,這時(shí)候Android提供了一個(gè)適配器類,叫作AnimatorListenerAdapter巩搏,使用這個(gè)類就可以解決掉實(shí)現(xiàn)接口繁瑣的問題了昨登,如下所示:

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

這里我們向addListener()方法中傳入這個(gè)適配器對(duì)象,由于AnimatorListenerAdapter中已經(jīng)將每個(gè)接口都實(shí)現(xiàn)好了贯底,所以這里不用實(shí)現(xiàn)任何一個(gè)方法也不會(huì)報(bào)錯(cuò)丰辣。那么如果我想監(jiān)聽動(dòng)畫結(jié)束這個(gè)事件,就只需要單獨(dú)重寫這一個(gè)方法就可以了禽捆,如下所示:

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


源碼


好了笙什,本篇就在此完結(jié)了,下篇文章我們重點(diǎn)解析屬性動(dòng)畫的類型和插值器

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末胚想,一起剝皮案震驚了整個(gè)濱河市琐凭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌浊服,老刑警劉巖统屈,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件胚吁,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡愁憔,警方通過查閱死者的電腦和手機(jī)腕扶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吨掌,“玉大人半抱,你說我怎么就攤上這事∧に危” “怎么了代虾?”我有些...
    開封第一講書人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)激蹲。 經(jīng)常有香客問我,道長(zhǎng)江掩,這世上最難降的妖魔是什么学辱? 我笑而不...
    開封第一講書人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮环形,結(jié)果婚禮上策泣,老公的妹妹穿的比我還像新娘。我一直安慰自己抬吟,他們只是感情好萨咕,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著火本,像睡著了一般危队。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上钙畔,一...
    開封第一講書人閱讀 52,441評(píng)論 1 310
  • 那天茫陆,我揣著相機(jī)與錄音,去河邊找鬼擎析。 笑死簿盅,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的揍魂。 我是一名探鬼主播桨醋,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼现斋!你這毒婦竟也來了喜最?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤步责,失蹤者是張志新(化名)和其女友劉穎返顺,沒想到半個(gè)月后禀苦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡遂鹊,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年振乏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片秉扑。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡慧邮,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出舟陆,到底是詐尸還是另有隱情误澳,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布秦躯,位于F島的核電站忆谓,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏踱承。R本人自食惡果不足惜倡缠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望茎活。 院中可真熱鬧昙沦,春花似錦、人聲如沸载荔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽懒熙。三九已至丘损,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間煌珊,已是汗流浹背号俐。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留定庵,地道東北人吏饿。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蔬浙,于是被迫代替她去往敵國(guó)和親猪落。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容