android動畫詳解(二)

Property Animation

簡單應(yīng)用兽狭、ofInt扬跋、ofFloat檐蚜、ofObject

在Property Animation中最常見的應(yīng)用就是ValueAnimator和ObjectAnimator這兩個類移层,?它們各自私有化了?它們的構(gòu)造方法身腻,所以在實際應(yīng)用中我們是通過他們的ofInt勋桶、ofFloat部凑、ofObject方法來獲取它們的實例蹭睡。
我們以O(shè)bjectAnimator為例:

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

ofFloat與ofInt方法表示我們將要改變的屬性的值是float雨涛、int類型枢舶,而當(dāng)屬性的值既不是float類型也不是int類型,這就需要使用ofObject

屬性動畫是在android3.0以后才有的替久,是對視圖動畫的一種擴展凉泄,我們先看它的幾種最基本實現(xiàn),然后再總結(jié)出屬性動畫到底在哪些方面做了改進蚯根。

switch (v.getId()) {
   case R.id.translate:
       ValueAnimator animator = ValueAnimator.ofInt(1);
       animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
        final float fraction = animation.getAnimatedFraction();
        int move = new IntEvaluator().evaluate(fraction,0,500);
        sample.setTranslationY(move);
     }
 });
      animator.setDuration(1000);
      animator.start();
     break;
   case R.id.alpha:
       ObjectAnimator alpha = ObjectAnimator.ofFloat(sample,"alpha",0,1);
       alpha.setDuration(1000);
       alpha.start();
      break;
   case R.id.rotate:
       ObjectAnimator rotate = ObjectAnimator.ofFloat(sample,"Rotation",0,180);
       rotate.setDuration(1000);
       rotate.start();
      break;
   case R.id.scale:
       AnimatorSet set = new AnimatorSet();
       ObjectAnimator scaleX = ObjectAnimator.ofFloat(sample,"scaleX",0.5f,1.5f);
       ObjectAnimator scaleY = ObjectAnimator.ofFloat(sample,"scaleY",0.5f,1.5f);
       set.playTogether(scaleX,scaleY);
       set.setDuration(1000);
       set.start();
      break;
case R.id.sample:
    Toast.makeText(this,"我被點擊 拉",Toast.LENGTH_SHORT).show();
   break;
 }

動畫效果如下:


這里寫圖片描述

通過上面的動畫演示后众,我們能總結(jié)出以下幾點:
1.通過View動畫能夠?qū)崿F(xiàn)的四種效果,通過Property?動畫也能實現(xiàn)
2.通過執(zhí)行完動畫后點擊sample按鈕可知颅拦,Property?動畫是真正的改變了按鈕的位置和屬性
3.ObjectAnimator是ValueAnimator的子類蒂誉,從實現(xiàn)看出,它比ValueAnimator要簡單距帅,所以在實際使用時右锨,我們大多使用的是ObkectAnimator
4.在ofFloat方法中要改變的屬性并不是隨意輸入的,屬性動畫要求對象的該屬性有set方法和get方法(可選)锥债。比如setAlpha()陡蝇。
5.由于結(jié)論4可知,我們要想實現(xiàn)Scale效果哮肚,必須同時使用"scaleX"和"scaleY"登夫,這是因為在Button中并沒有setScale()這個方法,需通過AnimatorSet來同時執(zhí)行兩個ObjectAnimator(還有另外一種更常用的方式——PropertyValuesHolder來實現(xiàn)多個動畫同時執(zhí)行的效果允趟,后文中將會詳細來說明)

PropertyValuesHolder

在ValueAnimator和ObjectAnimator這兩個類中我們發(fā)現(xiàn)還有一個ofPropertyValuesHolder方法恼策,下面將詳細介紹PropertyValuesHolder這個類。
PropertyValuesHolder 這個類的意義就是潮剪,它其中保存了動畫程中所需要操作的屬性和對應(yīng)的值涣楷。我們通ofFloat(Object target, String propertyName, float… values)構(gòu)造的動畫,ofFloat()的內(nèi)部實現(xiàn)其實就是將傳進來的參數(shù)封裝成 PropertyValuesHolder 實例來保存動畫狀態(tài)抗碰。在封裝成 PropertyValuesHolder 實例以后狮斗,后期的各種操作也是以 PropertyValuesHolder 為主的。 說到這里弧蝇,大家就知道這個 PropertyValuesHolder 是有多有用了吧碳褒,上面我們也說了折砸,ObjectAnimator 給我們提供了一個口子,讓我們自己構(gòu)造 PropertyValuesHolder 來構(gòu)造動畫沙峻。
下面這個應(yīng)用案例將使我們更深刻的理解它

 private void propertyValuesHolderAlarm(ImageView imageView) {
    PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("translationX",0,200);
    PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("alpha",0,1);
    PropertyValuesHolder holder3 = PropertyValuesHolder.ofFloat("rotation",0,180);
    PropertyValuesHolder holder4 = PropertyValuesHolder.ofFloat("scaleX",0.5f,1.5f,1.0f);
    PropertyValuesHolder holder5 = PropertyValuesHolder.ofFloat("scaleY",0.5f,1.5f);
    ObjectAnimator.ofPropertyValuesHolder(imageView,holder1,holder2,holder3,holder4,holder5).
                setDuration(1000).start();
 }

執(zhí)行的效果如下圖:

插值器睦授、估值器

要想更深入的理解android的動畫機制,插值器與估值器是我們必須要深入理解和掌握的知識摔寨。

插值器

ofInt(0,400)表示在一定的時間內(nèi)從0移動到400這個范圍去枷,但是我們有沒有想過在每一個時間節(jié)點中執(zhí)行動畫的對象所在的位置是如何確定的?這個時候就需要用到我們的插值器了是复。首先看下他們的結(jié)構(gòu)圖

這里寫圖片描述

作用:根據(jù)時間流逝的百分比來計算出屬性變化的百分比
然后看一下LinearInterpolator的實現(xiàn)

public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
    public LinearInterpolator() {
    }
    public LinearInterpolator(Context context, AttributeSet attrs) {
    }
    public float getInterpolation(float input) {
        return input;
    }
    /** @hide */
    @Override
    public long createNativeInterpolator() {
        return NativeInterpolatorFactoryHelper.createLinearInterpolator();
    }
}

這里最核心的一個方法就是getInterpolation(float input)删顶,他根據(jù)傳入過來的一個input通過一系列的計算后返回一個值,這個值就是計算出來的依據(jù)當(dāng)前的動畫執(zhí)行進度所確定的位置的一個計算值佑笋。如果用一句話來總結(jié)插值器的作用翼闹,那應(yīng)該就是插值器就是用來控制動畫區(qū)間的值被如何計算出來的。比如 LinearInterpolator 插值器就是勻速返回區(qū)間點的值蒋纬;而 DecelerateInterpolator 則表示開始變化快猎荠,后期變化慢;
下面這個圖片就是運用了插值器之后的效果:


這里寫圖片描述

估值器

在學(xué)習(xí)估值器之前我們先看一張圖片

這里寫圖片描述

這幅圖講述了從定義動畫的數(shù)字區(qū)間到通過 AnimatorUpdateListener 中得到當(dāng)前動畫所對應(yīng)數(shù)值的整個過程蜀备。下面我們對這四個步驟具體講解一下: (1)关摇、ofInt(0,400)表示指定動畫的數(shù)字區(qū)間,是從 0 運動到 400碾阁; (2)输虱、加速器:上面我們講了,在動畫開始后脂凶,通過加速器會返回當(dāng)前動畫進度所對應(yīng)的數(shù)字進度宪睹,但這個數(shù)字進度是百分制的,以小數(shù)表示蚕钦,如 0.2 (3)亭病、Evaluator:我們知道我們通過監(jiān)聽器拿到的是當(dāng)前動畫所對應(yīng)的具體數(shù)值,而不是百分制的進度嘶居。那么就必須有一個地方會根據(jù)當(dāng)前的數(shù)字進度罪帖,將其轉(zhuǎn)化為對應(yīng)的數(shù)值,這個地方就是 Evaluator邮屁;Evaluator 就是將從加速器返回的數(shù)字進度轉(zhuǎn)成對應(yīng)的數(shù)字值整袁。所以上部分中,我們講到的公式:
當(dāng)前的值 = 100 + (400 - 100)* 顯示進度
這個公式就是在 Evaluator 計算的佑吝;在拿到當(dāng)前數(shù)字進度所對應(yīng)的值以后坐昙,將其返回 (4)、監(jiān)聽器:我們通過在 AnimatorUpdateListener 監(jiān)聽器使用 animation.getAnimatedValue()函數(shù)拿到 Evaluator 中返回的數(shù)字值芋忿。 講了這么多民珍,Evaluator 其實就是一個轉(zhuǎn)換器襟士,他能把小數(shù)進度轉(zhuǎn)換成對應(yīng)的數(shù)值位置
依據(jù)屬性的變化的百分比計算出具體的數(shù)值
在一般的請款下插值器使用系統(tǒng)默認的插值器已足夠我們?nèi)粘J褂玫领灰獙傩灶愋筒皇莍nt嚷量、float、argb(顏色)我們常常需要自定義估值器逆趣。

應(yīng)用案例

我們知道蝶溶,在屬性動畫里能夠改變的屬性必須具備setXXX()和getXXX()方法(在某些情況下也可以沒有),可是在有些情況下我們就需要改變的屬性偏偏就沒有這些方法,這時我們該怎么辦宣渗?比如我們需要執(zhí)行一個動畫效果:改變TextView的字符類型抖所,這個方法在TextView中并未提供相應(yīng)set和get方法,在這種情況下痕囱,我們一般有如下三種解決方式:

  • ?給你的對象加上set和get方法田轧,如果你有權(quán)限的話
  • 用一個類包裝原始對象,間接為其提供set和get方法
  • 采用ValueAnimator鞍恢,監(jiān)聽動畫過程傻粘,自己實現(xiàn)屬性的變化

上面三種解決方案,以后兩種在日常使用中使用的頻率較高帮掉。下面就是上面案例解決的代碼

final ObjectAnimator objectAnimator = ObjectAnimator.ofObject(new TextViewWapper(tv)
                        , "char", new CharEvaluator(), new Character('A'), new Character('Z'));
objectAnimator.setDuration(2000);
objectAnimator.setInterpolator(new AccelerateInterpolator());
objectAnimator.start();
--------------------
    public class CharEvaluator implements TypeEvaluator<Character> {
        public Character evaluate(float fraction, Character startValue, Character endValue) {
            int startInt = (int)startValue;
            int endInt = (int)endValue;
            final int i = (int) (startInt + fraction * (endInt - startInt));
            char result = (char) i;
            return result;
        }
    }
 -------------------
     class TextViewWapper{
        private TextView mTarget;

        public TextViewWapper(TextView mTarget) {
            this.mTarget = mTarget;
        }

        public void setChar(Character character) {
            mTarget.setText(String.valueOf(character));
        }

    }

動畫執(zhí)行效果如下:


這里寫圖片描述

KeyFrame

我們知道如果要控制動畫速率的變化弦悉,我們可以通過自定義插值器,也可以通過自定義 Evaluator 來實現(xiàn)蟆炊。但如果真的讓我們?yōu)榱怂俾首兓Ч远x插值器或者 Evaluator 的話稽莉,恐怕大部分同學(xué)會有一萬頭草泥馬在眼前奔過,因為大部分的同學(xué)的數(shù)學(xué)知識已經(jīng)還給老師了涩搓。 為了解決方便的控制動畫速率的問題污秆,谷歌定義了一個 KeyFrame 的類,KeyFrame 直譯過來就是關(guān)鍵幀昧甘。 關(guān)鍵幀這個概念是從動畫里學(xué)來的良拼,我們知道視頻里,一秒要播放 24 幀圖片疾层,對于制作 flash 動畫的同學(xué)來講将饺,是不是每一幀都要畫出來呢?當(dāng)然不是了痛黎;比如我們要讓一個球在 30 秒時間內(nèi)予弧,從(0,0)點運動到(300,200)點湖饱,那 flash 是怎么來做的呢掖蛤,在 flash 中,我們只需要定義兩個關(guān)鍵幀井厌,在動畫開始時定義一個蚓庭,把球的位置放在(0,0)點致讥;在 30 秒后,再定義一個關(guān)鍵幀器赞,把球的位置放在(300垢袱,200)點。在動畫 開始時港柜,球初始在是(0请契,0)點,30 秒時間內(nèi)就 adobe flash 就會自動填充夏醉,把球平滑移動到第二個關(guān)鍵幀的位置(300爽锥,200)點; 通過上面分析 flash 動畫的制作原理畔柔,我們知道氯夷,一個關(guān)鍵幀必須包含兩個原素,第一時間點靶擦,第二位置腮考。即這個關(guān)鍵幀是表示的是某個物體在哪個時間點應(yīng)該在哪個位置上。 所以谷歌的 KeyFrame 也不例外奢啥,KeyFrame 的生成方式為:

Keyframe kf0 = Keyframe.ofFloat(0, 0);  
Keyframe kf1 = Keyframe.ofFloat(0.1f, -20f);  
Keyframe kf2 = Keyframe.ofFloat(1f, 0);

public static Keyframe ofFloat(float fraction, float value) 

fraction:表示當(dāng)前的顯示進度秸仙,即從加速器中 getInterpolation()函數(shù)的返回值;
value:表示當(dāng)前應(yīng)該在的位置 比如 Keyframe.ofFloat(0, 0)表示動畫進度為 0 時桩盲,動畫所在的數(shù)值位置為 0寂纪;Keyframe.ofFloat(0.25f, -20f)表示動畫進度為 25%時,動畫所在的數(shù)值位置為-20赌结;Keyframe.ofFloat(1f,0)表示動畫結(jié)束時捞蛋,動畫所在的數(shù)值位置為 0; 在理解了 KeyFrame.ofFloat()的參數(shù)以后柬姚,我們來看看 PropertyValuesHolder 是如何使用 KeyFrame 對象的:

Keyframe frame0 = Keyframe.ofFloat(0f, 0);  
Keyframe frame1 = Keyframe.ofFloat(0.1f, -20f);  
Keyframe frame2 = Keyframe.ofFloat(1, 0);  
PropertyValuesHolder frameHolder = PropertyValuesHolder.ofKeyframe("rotation",frame0,frame1,frame2);  
 Animator animator = ObjectAnimator.ofPropertyValuesHolder(mImage,frameHolder);  
animator.setDuration(1000);  
animator.start(); 

動畫的執(zhí)行效果如下:


這里寫圖片描述

總結(jié)

1.Property Animator 是通過改變控件某一屬性值來做動畫的
2.Property Animator 能實現(xiàn)補間動畫無法實現(xiàn)的功能
3.補間動畫雖能對控件做動畫拟杉,但并沒有改變控件內(nèi)部的屬性值。而 Property Animator 則是恰恰相反量承,Property Animator 是通過改變控件內(nèi)部的屬性值來達到動畫效果的,視圖動畫只是改變了View得繪制位置搬设,并沒有改變View的位置本身。比如一個Button通過位移動畫移動到一個位置撕捍,但是你在原位置能執(zhí)行點擊動畫拿穴,因為button本身并沒有發(fā)生變化
With the property animation system, these constraints are completely removed, and you can animate any property of any object (Views and non-Views) and the object itself is actually modified.
The view animation system, however, takes less time to setup and requires less code to write.
所以如果視圖動畫能夠滿足你的要求,用視圖動畫
4.屬性動畫最大的問題也許就是兼容性了忧风,因為它只適用于android3.0以上的系統(tǒng)默色,使用nineoldandroids可以兼容android3.0一下系統(tǒng),可是其本質(zhì)仍然是視圖動畫狮腿。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末腿宰,一起剝皮案震驚了整個濱河市呕诉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌吃度,老刑警劉巖甩挫,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異规肴,居然都是意外死亡捶闸,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門拖刃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人贪绘,你說我怎么就攤上這事兑牡。” “怎么了税灌?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵均函,是天一觀的道長。 經(jīng)常有香客問我菱涤,道長苞也,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任粘秆,我火速辦了婚禮如迟,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘攻走。我一直安慰自己殷勘,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布昔搂。 她就那樣靜靜地躺著玲销,像睡著了一般。 火紅的嫁衣襯著肌膚如雪摘符。 梳的紋絲不亂的頭發(fā)上贤斜,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天,我揣著相機與錄音逛裤,去河邊找鬼瘩绒。 笑死,一個胖子當(dāng)著我的面吹牛别凹,可吹牛的內(nèi)容都是我干的草讶。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼炉菲,長吁一口氣:“原來是場噩夢啊……” “哼堕战!你這毒婦竟也來了坤溃?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤嘱丢,失蹤者是張志新(化名)和其女友劉穎薪介,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體越驻,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡汁政,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了缀旁。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片记劈。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖并巍,靈堂內(nèi)的尸體忽然破棺而出目木,到底是詐尸還是另有隱情,我是刑警寧澤懊渡,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布刽射,位于F島的核電站,受9級特大地震影響剃执,放射性物質(zhì)發(fā)生泄漏誓禁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一肾档、第九天 我趴在偏房一處隱蔽的房頂上張望摹恰。 院中可真熱鬧,春花似錦阁最、人聲如沸戒祠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽姜盈。三九已至,卻和暖如春配阵,著一層夾襖步出監(jiān)牢的瞬間馏颂,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工棋傍, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留救拉,地道東北人。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓瘫拣,卻偏偏與公主長得像亿絮,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,713評論 2 354

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