Android動(dòng)畫機(jī)制總結(jié)筆記--屬性動(dòng)畫PropertyAnimation篇之ObjectAnimator

注意:本篇文章是本人閱讀關(guān)于Android動(dòng)畫的文章所寫下的總結(jié)葵腹,方便以后查閱琐脏,所有內(nèi)容非原創(chuàng),侵權(quán)刪坚嗜。

本篇文章內(nèi)容來自于

  1. Android高級(jí)進(jìn)階 顧浩鑫
  2. Android自定義控件三部曲文章索引之動(dòng)畫篇

目錄

4.屬性動(dòng)畫PropertyAnimation(基類Animator)
--4.2 ObjectAnimator(ValueAnimator的子類 實(shí)際開發(fā)中最常用)
----4.2.1 ObjectAnimator構(gòu)造方法(5種)
----4.2.2 ObjectAnimator代碼實(shí)現(xiàn)
------4.2.2.1 ofInt ofFloat ofObject構(gòu)造
------4.2.2.2 ofPropertyValuesHolder構(gòu)造
----4.2.3 ObjectAnimator動(dòng)畫原理
----4.2.4 ObjectAnimator XML實(shí)現(xiàn)

4.屬性動(dòng)畫PropertyAnimation(基類Animator)

一個(gè)完整的屬性動(dòng)畫由兩部分組成:
1.計(jì)算動(dòng)畫各個(gè)幀的相關(guān)屬性值
2.將這些屬性值設(shè)置給指定的對(duì)象

4.2 ObjectAnimator(ValueAnimator的子類 實(shí)際開發(fā)中最常用)

是ValueAnimator的子類,封裝實(shí)現(xiàn)了第二部分功能继蜡。
實(shí)際開發(fā)用到的更多的是ObjectAnimator回俐,只有在ObjectAnimator實(shí)現(xiàn)不了的情景下,才考慮使用ValueAnimator

4.2.1 ObjectAnimator構(gòu)造方法

由于ObjectAnimator是派生自ValueAnimator的稀并,所以ValueAnimator中所能使用的方法仅颇,在ObjectAnimator中都可以正常使用。
但ObjectAnimator也重寫了幾個(gè)方法碘举,比如ofInt(),ofFloat()等忘瓦。

public static ObjectAnimator ofInt(Object target, String propertyName, int... values)
public static ObjectAnimator ofArgb(Object target, String propertyName, int... values) 
public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) 
public static ObjectAnimator ofObject(Object target, String propertyName,TypeEvaluator evaluator, Object... values) 
public static ObjectAnimator ofPropertyValuesHolder(Object target,PropertyValuesHolder... values) 

4.2.2 ObjectAnimator代碼實(shí)現(xiàn)

4.2.2.1 ofInt ofFloat ofObject
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(tvAnimPropertyObject, "rotation", 0,180,0);
objectAnimator.setDuration(3000);
objectAnimator.start();

ObjectAnimator做動(dòng)畫,并不是根據(jù)控件xml中的屬性來改變的引颈,而是通過指定屬性所對(duì)應(yīng)的set方法來改變的耕皮。

比如,我們上面指定的改變r(jià)otation的屬性值蝙场,ObjectAnimator在做動(dòng)畫時(shí)就會(huì)到指定控件(TextView)中去找對(duì)應(yīng)的setRotation()方法來改變控件中對(duì)應(yīng)的值凌停。

在View中有關(guān)動(dòng)畫,總共有下面幾組set方法:

//1售滤、透明度:alpha
public void setAlpha(float alpha)
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(tvAnimPropertyObject, "alpha", 1, 0, 1);

//2罚拟、旋轉(zhuǎn)度數(shù):rotation、rotationX、rotationY
public void setRotation(float rotation) 表示旋轉(zhuǎn)度數(shù)
public void setRotationX(float rotationX) 表示旋轉(zhuǎn)度數(shù)
public void setRotationY(float rotationY) 表示旋轉(zhuǎn)度數(shù)
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(tvAnimPropertyObject, "rotation", 0,180,0);

//3舟舒、平移:translationX拉庶、translationY
public void setTranslationX(float translationX) 向右為正方向
public void setTranslationY(float translationY) 向下為正方向
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(tvAnimPropertyObject, "translationX", 0, 200, -200,0);

//縮放:scaleX、scaleY
public void setScaleX(float scaleX) scaleX表示縮放倍數(shù)
public void setScaleY(float scaleY) scaleY表示縮放倍數(shù)
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(tvAnimPropertyObject, "scaleX", 0, 3, 1);

使用時(shí)要注意


關(guān)于屬性的get方法
當(dāng)且僅當(dāng)我們?cè)趧?chuàng)建ObjectAnimator時(shí)秃励,只給他傳遞了一個(gè)過渡值的時(shí)候氏仗,系統(tǒng)才會(huì)調(diào)用屬性對(duì)應(yīng)的get函數(shù)來得到動(dòng)畫的初始值!

4.2.2.2 ofPropertyValuesHolder

構(gòu)造方法如下

public static ObjectAnimator ofPropertyValuesHolder(Object target,PropertyValuesHolder... values)  
4.2.2.2.1.什么是PropertyValuesHolder

PropertyValuesHolder這個(gè)類的意義就是夺鲜,它其中保存了動(dòng)畫過程中所需要操作的屬性和對(duì)應(yīng)的值皆尔。
我們通過ofFloat(Object target, String propertyName, float… values)構(gòu)造的動(dòng)畫,ofFloat()的內(nèi)部實(shí)現(xiàn)其實(shí)就是將傳進(jìn)來的參數(shù)封裝成PropertyValuesHolder實(shí)例來保存動(dòng)畫狀態(tài)币励。在封裝成PropertyValuesHolder實(shí)例以后慷蠕,后期的各種操作也是以PropertyValuesHolder為主的。
ObjectAnimator給我們提供了一個(gè)口子食呻,讓我們自己構(gòu)造PropertyValuesHolder來構(gòu)造動(dòng)畫流炕。

4.2.2.2.2 PropertyValuesHolder構(gòu)造函數(shù)
public static PropertyValuesHolder ofFloat(String propertyName, float... values)  
public static PropertyValuesHolder ofInt(String propertyName, int... values)   
public static PropertyValuesHolder ofObject(String propertyName, TypeEvaluator evaluator,Object... values)  
public static PropertyValuesHolder ofKeyframe(String propertyName, Keyframe... values) 
4.2.2.2.2 PropertyValuesHolder常用方法
//設(shè)置動(dòng)畫的Evaluator 
public void setEvaluator(TypeEvaluator evaluator)  
//用于設(shè)置ofFloat所對(duì)應(yīng)的動(dòng)畫值列表 
public void setFloatValues(float... values)  
//用于設(shè)置ofInt所對(duì)應(yīng)的動(dòng)畫值列表 
public void setIntValues(int... values)  
//用于設(shè)置ofKeyframe所對(duì)應(yīng)的動(dòng)畫值列表 
public void setKeyframes(Keyframe... values)  
//用于設(shè)置ofObject所對(duì)應(yīng)的動(dòng)畫值列表 
public void setObjectValues(Object... values)  
//設(shè)置動(dòng)畫屬性名 
public void setPropertyName(String propertyName) 

setFloatValues(float… values)對(duì)應(yīng)PropertyValuesHolder.ofFloat(),用于動(dòng)態(tài)設(shè)置動(dòng)畫中的數(shù)值仅胞。setIntValues每辟、setKeyframes、setObjectValues同理干旧;
setPropertyName用于設(shè)置PropertyValuesHolder所需要操作的動(dòng)畫屬性名;

4.2.2.2.3 使用PropertyValuesHolder創(chuàng)建ObjectAnimator

1??ofFloat ofInt

PropertyValuesHolder rotation = PropertyValuesHolder.ofFloat("rotation", 60f, -60f, 40f, -40f, -20f, 20f, 10f, -10f, 0f);
PropertyValuesHolder backgroundColor = PropertyValuesHolder.ofInt("BackgroundColor", 0xffffffff, 0xffff00ff, 0xffffff00, 0xffffffff);
ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(tvAnimPropertyObject, rotation, backgroundColor);
objectAnimator.setDuration(3000);
objectAnimator.setInterpolator(new AccelerateInterpolator());
objectAnimator.start();

2??ofObject

PropertyValuesHolder charText = PropertyValuesHolder.ofObject("CharText", new CharEvaluator(), new Character('A'), new Character('Z'));
ObjectAnimator objectAnimator1 = ObjectAnimator.ofPropertyValuesHolder(mtvAnimPropertyObject, charText);
objectAnimator1.setDuration(3000);
objectAnimator1.start();

3??ofKeyFrame
① 什么是keyFrame
如果要控制動(dòng)畫速率的變化渠欺,我們可以通過自定義插值器,也可以通過自定義Evaluator來實(shí)現(xiàn)椎眯。但有一定的難度挠将。為了解決方便的控制動(dòng)畫速率的問題,谷歌定義了一個(gè)KeyFrame的類编整,也就是關(guān)鍵幀舔稀。

就是類似動(dòng)畫中的關(guān)鍵幀:
比如我們要讓一個(gè)球在30秒時(shí)間內(nèi),從(0,0)點(diǎn)運(yùn)動(dòng)到(300掌测,200)點(diǎn)镶蹋,我們只需要定義兩個(gè)關(guān)鍵幀,在動(dòng)畫開始時(shí)定義一個(gè)赏半,把球的位置放在(0,0)點(diǎn)贺归;在30秒后,再定義一個(gè)關(guān)鍵幀断箫,把球的位置放在(300拂酣,200)點(diǎn)。在動(dòng)畫 開始時(shí)仲义,球初始在是(0婶熬,0)點(diǎn)剑勾,30秒時(shí)間內(nèi)就adobe flash就會(huì)自動(dòng)填充,把球平滑移動(dòng)到第二個(gè)關(guān)鍵幀的位置(300赵颅,200)點(diǎn)虽另;

一個(gè)關(guān)鍵幀必須包含兩個(gè)原素,第一時(shí)間點(diǎn)饺谬,第二位置捂刺。即這個(gè)關(guān)鍵幀是表示的是某個(gè)物體在哪個(gè)時(shí)間點(diǎn)應(yīng)該在哪個(gè)位置上。

② KeyFrame 構(gòu)造方法

// ofFloat 
public static Keyframe ofFloat(float fraction)   
public static Keyframe ofFloat(float fraction, float value)  
//ofInt 
public static Keyframe ofInt(float fraction)  
public static Keyframe ofInt(float fraction, int value) 
//ofObject
public static Keyframe ofObject(float fraction, Object value)
public static Keyframe ofObject(float fraction)

public static Keyframe ofFloat(float fraction, float value)

  • fraction:表示當(dāng)前的顯示進(jìn)度募寨,即從加速器中g(shù)etInterpolation()函數(shù)的返回值族展;
  • value:表示當(dāng)前應(yīng)該在的位置

Keyframe kf0 = Keyframe.ofFloat(0, 0);
Keyframe kf1 = Keyframe.ofFloat(0.1f, -20f);
Keyframe kf2 = Keyframe.ofFloat(1f, 0);
比如Keyframe.ofFloat(0, 0)表示動(dòng)畫進(jìn)度為0時(shí),動(dòng)畫所在的數(shù)值位置為0拔鹰;Keyframe.ofFloat(0.25f, -20f)表示動(dòng)畫進(jìn)度為25%時(shí)仪缸,動(dòng)畫所在的數(shù)值位置為-20;Keyframe.ofFloat(1f,0)表示動(dòng)畫結(jié)束時(shí)列肢,動(dòng)畫所在的數(shù)值位置為0恰画;

public static Keyframe ofFloat(float fraction)

  • 參數(shù)fraction,表示當(dāng)前關(guān)鍵幀所在的動(dòng)畫進(jìn)度位置瓷马。

那在這個(gè)進(jìn)度時(shí)所對(duì)應(yīng)的值 用setValue來設(shè)置

③KeyFrame常用方法

//設(shè)置fraction參數(shù)拴还,即Keyframe所對(duì)應(yīng)的進(jìn)度 
public void setFraction(float fraction)   
//設(shè)置當(dāng)前Keyframe所對(duì)應(yīng)的值 
public void setValue(Object value)  
//設(shè)置Keyframe動(dòng)作期間所對(duì)應(yīng)的插值器 
public void setInterpolator(TimeInterpolator interpolator)  

③ 代碼實(shí)現(xiàn)
1.使用ofFloat/ofInt構(gòu)造KeyFrame

Keyframe frame0 = Keyframe.ofFloat(0f, 0);
Keyframe frame1 = Keyframe.ofFloat(0.1f, -20f);
Keyframe frame2 = Keyframe.ofFloat(1, 0);
PropertyValuesHolder propertyValuesHolder = PropertyValuesHolder.ofKeyframe("rotation", frame0, frame1, frame2);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofPropertyValuesHolder(tvAnimPropertyObject, propertyValuesHolder);
objectAnimator2.setDuration(3000);
objectAnimator2.start();

2.使用ofObject構(gòu)造KeyFrame

Keyframe frame_0 = Keyframe.ofObject(0f, new Character('A'));
Keyframe frame_1 = Keyframe.ofObject(0.1f, new Character('L'));
Keyframe frame_2 = Keyframe.ofObject(1, new Character('Z'));
PropertyValuesHolder propertyValuesHolder1 = PropertyValuesHolder.ofKeyframe("CharText", frame_0, frame_1, frame_2);
propertyValuesHolder1.setEvaluator(new CharEvaluator());
ObjectAnimator objectAnimator3 = ObjectAnimator.ofPropertyValuesHolder(mtvAnimPropertyObject, propertyValuesHolder1);
objectAnimator3.setDuration(3000);
objectAnimator3.start();

④ 關(guān)于KeyFrame的插值器的注意點(diǎn)
關(guān)鍵幀可通過以下方法設(shè)置插值器

//設(shè)置Keyframe動(dòng)作期間所對(duì)應(yīng)的插值器 
public void setInterpolator(TimeInterpolator interpolator)  

如果給這個(gè)Keyframe設(shè)置上插值器,
那么這個(gè)插值器就是從上一個(gè)Keyframe開始到當(dāng)前設(shè)置插值器的Keyframe時(shí)决采,這個(gè)過程值的計(jì)算是利用這個(gè)插值器的

Keyframe frame0 = Keyframe.ofFloat(0f, 0);  
Keyframe frame1 = Keyframe.ofFloat(0.1f, -20f);  
frame1.setInterpolator(new BounceInterpolator());

在frame0到frame1的中間值計(jì)算過程中,就是用的就是回彈插值坟奥。
給Keyframe.ofFloat(0f, 0)設(shè)置插值器是無效的树瞭,因?yàn)樗堑谝粠?/p>

⑤ 關(guān)于關(guān)鍵幀KeyFrame的注意點(diǎn)
如果去掉第0幀(fraction為0),將以第一個(gè)關(guān)鍵幀為起始位置
如果去掉結(jié)束幀(fraction為1)爱谁,將以最后一個(gè)關(guān)鍵幀為結(jié)束位置
使用Keyframe來構(gòu)建動(dòng)畫晒喷,至少要有兩個(gè)或兩個(gè)以上幀,否則會(huì)崩

4.2.3 ObjectAnimator動(dòng)畫原理


1??首先通過加速器產(chǎn)生當(dāng)前進(jìn)度的百分比访敌,
然后再經(jīng)過Evaluator生成對(duì)應(yīng)百分比所對(duì)應(yīng)的數(shù)字值凉敲。
這兩步與ValueAnimator是完全一樣的,

2??唯一不同的是最后一步
在ValueAnimator中寺旺,我們要通過添加監(jiān)聽器來監(jiān)聽當(dāng)前數(shù)字值爷抓。
而在ObjectAnimator中,則是先根據(jù)屬性值拼裝成對(duì)應(yīng)的set函數(shù)的名字阻塑,比如這里的scaleY的拼裝方法就是將屬性的第一個(gè)字母強(qiáng)制大寫后蓝撇,與set拼接,所以就是setScaleY陈莽。然后通過反射找到對(duì)應(yīng)控件的setScaleY(float scaleY)函數(shù)渤昌,將當(dāng)前數(shù)字值做為setScaleY(float scale)的參數(shù)將其傳入虽抄。

3??調(diào)用完set方法,set方法內(nèi)部會(huì)對(duì)控件進(jìn)行設(shè)置独柑,動(dòng)畫在進(jìn)行時(shí)每隔十幾毫秒會(huì)刷新一次迈窟,set函數(shù)也會(huì)每隔十幾毫秒會(huì)被調(diào)用一次(將動(dòng)畫中間值傳給他)。

4.2.4 ObjectAnimator XML實(shí)現(xiàn)

標(biāo)簽<objectAnimator />對(duì)應(yīng)ObjectAnimator

4.2.4.1 <objectAnimator />標(biāo)簽字段意義及使用方法

<objectAnimator
    android:propertyName="string"
    android:duration="int"
    android:valueFrom="float | int | color"
    android:valueTo="float | int | color"
    android:startOffset="int"
    android:repeatCount="int"
    android:repeatMode=["repeat" | "reverse"]
    android:valueType=["intType" | "floatType"]
    android:interpolator=["@android:interpolator/XXX"]/>

android:propertyName:對(duì)應(yīng)屬性名忌栅,即ObjectAnimator所需要操作的屬性名车酣。
android:valueType:表示參數(shù)值類型,取值為intType和floatType狂秘;與android:valueFrom骇径、android:valueTo相對(duì)應(yīng)。

4.2.4.2 代碼實(shí)現(xiàn)

  1. res/animator新建animtor_object.xml
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:propertyName="TranslationY"
    android:duration="2000"
    android:valueFrom="0.0"
    android:valueTo="400.0"
    android:valueType="floatType"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    android:repeatCount="1"
    android:repeatMode="reverse"
    android:startOffset="2000"
    />
  1. 加載動(dòng)畫
ObjectAnimator animator = (ObjectAnimator) AnimatorInflater.loadAnimator(this, R.animator.animator_object);
animator.setTarget(tvAnimPropertyObject);
animator.start();

更多案例

ObjectAnimator運(yùn)用在自定義控件(彈性圓)上

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末者春,一起剝皮案震驚了整個(gè)濱河市破衔,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌钱烟,老刑警劉巖晰筛,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異拴袭,居然都是意外死亡读第,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門拥刻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來怜瞒,“玉大人,你說我怎么就攤上這事般哼∥馔簦” “怎么了?”我有些...
    開封第一講書人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵蒸眠,是天一觀的道長漾橙。 經(jīng)常有香客問我,道長楞卡,這世上最難降的妖魔是什么霜运? 我笑而不...
    開封第一講書人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮蒋腮,結(jié)果婚禮上淘捡,老公的妹妹穿的比我還像新娘。我一直安慰自己池摧,他們只是感情好案淋,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著险绘,像睡著了一般踢京。 火紅的嫁衣襯著肌膚如雪誉碴。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,829評(píng)論 1 290
  • 那天瓣距,我揣著相機(jī)與錄音黔帕,去河邊找鬼。 笑死蹈丸,一個(gè)胖子當(dāng)著我的面吹牛成黄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播逻杖,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼奋岁,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了荸百?” 一聲冷哼從身側(cè)響起闻伶,我...
    開封第一講書人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎够话,沒想到半個(gè)月后蓝翰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡女嘲,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年畜份,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片欣尼。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡爆雹,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出愕鼓,到底是詐尸還是另有隱情钙态,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布拒啰,位于F島的核電站驯绎,受9級(jí)特大地震影響完慧,放射性物質(zhì)發(fā)生泄漏谋旦。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一屈尼、第九天 我趴在偏房一處隱蔽的房頂上張望册着。 院中可真熱鬧,春花似錦脾歧、人聲如沸甲捏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽司顿。三九已至芒粹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間大溜,已是汗流浹背化漆。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留钦奋,地道東北人座云。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像付材,于是被迫代替她去往敵國和親朦拖。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349