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閱讀 227,533評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,055評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,365評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,561評(píng)論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,346評(píng)論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,889評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,978評(píng)論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,118評(píng)論 0 286
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,637評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,558評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,739評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,246評(píng)論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 43,980評(píng)論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,619評(píng)論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,347評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,702評(píng)論 2 370