鍍金池/ 教程/ Android/ PropertyValuesHolder 與 Keyframe
聯(lián)合動(dòng)畫的 XML 實(shí)現(xiàn)與使用示例
Interpolator 插值器
高級(jí)進(jìn)階(二)
ObjectAnimator 基本使用
ValueAnimator 基本使用
alpha、scale、translate、rotate、set 的 xml 屬性及用法
PropertyValuesHolder 與 Keyframe
layoutAnimation 與 gridLayoutAnimation
自定義控件三部曲之動(dòng)畫篇(十三)——實(shí)現(xiàn)ListView Item進(jìn)入動(dòng)畫
自定義控件三部曲之動(dòng)畫篇(十二)——animateLayoutChanges與LayoutTransition
高級(jí)進(jìn)階(一)
代碼生成 alpha、scale、translate、rotate、set 及插值器動(dòng)畫
聯(lián)合動(dòng)畫的代碼實(shí)現(xiàn)

PropertyValuesHolder 與 Keyframe

前幾篇給大家講了 ValueAnimator、ObjectAnimator 的知識(shí),講解了它們 ofInt(),ofFloat(),ofObject()函數(shù)的用法。細(xì)心的同學(xué)可能會(huì)注意到,ValueAnimator、ObjectAnimator 除了這些創(chuàng)建 Animator 實(shí)例的方法以外,都還有一個(gè)方法:

/** 
 * valueAnimator 的 
 */  
public static ValueAnimator ofPropertyValuesHolder(PropertyValuesHolder... values)   
/** 
 * ObjectAnimator 的 
 */  
public static ObjectAnimator ofPropertyValuesHolder(Object target,PropertyValuesHolder... values)  

也就是說(shuō) ValueAnimator 和 ObjectAnimator 除了通過(guò) ofInt(),ofFloat(),ofObject()創(chuàng)建實(shí)例外,還都有一個(gè) ofPropertyValuesHolder()方法來(lái)創(chuàng)建實(shí)例,這篇文章我就帶大家來(lái)看看如何通過(guò) ofPropertyValuesHolder()來(lái)創(chuàng)建實(shí)例的。 由于 ValueAnimator 和 ObjectAnimator 都具有 ofPropertyValuesHolder()函數(shù),使用方法也差不多,相比而言,ValueAnimator 的使用機(jī)會(huì)不多,這里我們就只講 ObjectAnimator 中 ofPropertyValuesHolder()的用法。相信大家懂了這篇以后,再去看 ValueAnimator 的 ofPropertyValuesHolder(),也應(yīng)該是會(huì)用的。 在這篇文章的最后,我們通過(guò)本篇內(nèi)容做了一個(gè)電話響鈴的效果,效果圖如下:

http://wiki.jikexueyuan.com/project/android-animation/images/81.gif" alt="" />

(錄的圖片效果不好,實(shí)際顯示時(shí)抖的是更厲害的,大家可以看源碼效果)

一、PropertyValuesHolder

1、概述

PropertyValuesHolder 這個(gè)類的意義就是,它其中保存了動(dòng)畫過(guò)程中所需要操作的屬性和對(duì)應(yīng)的值。我們通過(guò) ofFloat(Object target, String propertyName, float… values)構(gòu)造的動(dòng)畫,ofFloat()的內(nèi)部實(shí)現(xiàn)其實(shí)就是將傳進(jìn)來(lái)的參數(shù)封裝成 PropertyValuesHolder 實(shí)例來(lái)保存動(dòng)畫狀態(tài)。在封裝成 PropertyValuesHolder 實(shí)例以后,后期的各種操作也是以 PropertyValuesHolder 為主的。 說(shuō)到這里,大家就知道這個(gè) PropertyValuesHolder 是有多有用了吧,上面我們也說(shuō)了,ObjectAnimator 給我們提供了一個(gè)口子,讓我們自己構(gòu)造 PropertyValuesHolder 來(lái)構(gòu)造動(dòng)畫。

public static ObjectAnimator ofPropertyValuesHolder(Object target,PropertyValuesHolder... values)  

PropertyValuesHolder 中有很多函數(shù),有些函數(shù)的 api 等級(jí)是 11,有些函數(shù)的 api 等級(jí)是 14 和 21; 高 api 的函數(shù)我們就不講了,只講講 api 11 的函數(shù)的用法。有關(guān)各個(gè)函數(shù)的 api 等級(jí),大家可以參考《Google 文檔:PropertyValuesHolder》 首先,我們來(lái)看看創(chuàng)建實(shí)例的函數(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)  

這里總共有四個(gè)創(chuàng)建實(shí)例的方法,這一段我們著重講 ofFloat、ofInt 和 ofObject 的用法,ofKeyframe 我們單獨(dú)講。

2、PropertyValuesHolder 之 ofFloat()、ofInt()

(1)ofFloat()、ofInt() 我們先來(lái)看看它們的構(gòu)造函數(shù):

public static PropertyValuesHolder ofFloat(String propertyName, float... values)  
public static PropertyValuesHolder ofInt(String propertyName, int... values) 

其中:

  • propertyName:表示 ObjectAnimator 需要操作的屬性名。即 ObjectAnimator 需要通過(guò)反射查找對(duì)應(yīng)屬性的 setProperty()函數(shù)的那個(gè) property.
  • values:屬性所對(duì)應(yīng)的參數(shù),同樣是可變長(zhǎng)參數(shù),可以指定多個(gè),還記得我們?cè)?ObjectAnimator 中講過(guò),如果只指定了一個(gè),那么 ObjectAnimator 會(huì)通過(guò)查找 getProperty()方法來(lái)獲得初始值。不理解的同學(xué)請(qǐng)參看《Animation 動(dòng)畫詳解(七)——ObjectAnimator 基本使用》 大家看這些參數(shù)是不是很眼熟,讓我們看一下 ObjectAnimator 的 ofFloat 是怎么樣的:
public static ObjectAnimator ofFloat(Object target, String propertyName, float... values);

看到?jīng)],在 ObjectAnimator.ofFloat 中只比 PropertyValuesHolder 的 ofFloat 多了一個(gè) target,其它都是完全一樣的! 好了,我們?cè)谥v完 PropertyValuesHolder 的 ofFloat 函數(shù)以后,我們?cè)賮?lái)看看如何將構(gòu)造的 PropertyValuesHolder 實(shí)例設(shè)置進(jìn) ObjectAnimator 吧。

(2)、ObjectAnimator.ofPropertyValuesHolder() 在開(kāi)篇時(shí),我們也講了 ObjectAnimator 給我們提供了一個(gè)設(shè)置 PropertyValuesHolder 實(shí)例的入口:

public static ObjectAnimator ofPropertyValuesHolder(Object target,PropertyValuesHolder... values)

其中:

  • target:指需要執(zhí)行動(dòng)畫的控件
  • values:是一個(gè)可變長(zhǎng)參數(shù),可以傳進(jìn)去多個(gè) PropertyValuesHolder 實(shí)例,由于每個(gè) PropertyValuesHolder 實(shí)例都會(huì)針對(duì)一個(gè)屬性做動(dòng)畫,所以如果傳進(jìn)去多個(gè) PropertyValuesHolder 實(shí)例,將會(huì)對(duì)控件的多個(gè)屬性同時(shí)做動(dòng)畫操作。

(3)、示例 下面我們就舉個(gè)例子來(lái)如何通過(guò) PropertyValuesHolder 的 ofFloat、ofInt 來(lái)做動(dòng)畫的。 效果圖如下:

http://wiki.jikexueyuan.com/project/android-animation/images/82.gif" alt="" />

這個(gè)動(dòng)畫很簡(jiǎn)單,就是在點(diǎn)擊按鈕的時(shí)候,給 textView 做動(dòng)畫,框架代碼就不再講了,我們主要來(lái)看看操作 textview 動(dòng)畫的代碼。 動(dòng)畫代碼為:

PropertyValuesHolder rotationHolder = PropertyValuesHolder.ofFloat("Rotation", 60f, -60f, 40f, -40f, -20f, 20f, 10f, -10f, 0f);  
PropertyValuesHolder colorHolder = PropertyValuesHolder.ofInt("BackgroundColor", 0xffffffff, 0xffff00ff, 0xffffff00, 0xffffffff);  
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(mTextView, rotationHolder, colorHolder);  
animator.setDuration(3000);  
animator.setInterpolator(new AccelerateInterpolator());  
animator.start();  

在這里,我們創(chuàng)建了兩個(gè) PropertyValuesHolder 實(shí)例,第一個(gè) rotationHolder:

PropertyValuesHolder rotationHolder = PropertyValuesHolder.ofFloat("Rotation", 60f, -60f, 40f, -40f, -20f, 20f, 10f, -10f, 0f);  

使用 ofFloat 函數(shù)創(chuàng)建,屬性值是 Rotation,對(duì)應(yīng)的是 View 類中 SetRotation(float rotation)函數(shù)。后面?zhèn)鬟M(jìn)去很多值,讓其左右擺動(dòng)。 第二是動(dòng)畫是改變背景色的 colorHolder

PropertyValuesHolder colorHolder = PropertyValuesHolder.ofInt("BackgroundColor", 0xffffffff, 0xffff00ff, 0xffffff00, 0xffffffff); 

這里使用的是 ofInt 函數(shù)創(chuàng)建的,它操作的屬性是 BackgroundColor,對(duì)應(yīng)的是 View 類中的 setBackgroundColor(int color)函數(shù),后面?zhèn)鬟M(jìn)去的 16 進(jìn)制顏色值讓其在這些顏色值間變化。有關(guān)顏色值的變化,大家可以參考《Animation 動(dòng)畫詳解(七)——ObjectAnimator 基本使用》中第三部分《常用函數(shù)》 最后通過(guò) ObjectAnimator.ofPropertyValuesHolder 將 rotationHolder、colorHolder 設(shè)置給 mTextView,構(gòu)造出 ObjectAnimator 對(duì)象。然后開(kāi)始動(dòng)畫即可

ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(mTextView, rotationHolder, colorHolder);  
animator.setDuration(3000);  
animator.setInterpolator(new AccelerateInterpolator());  
animator.start();

好了,到這里有關(guān) PropertyValuesHolder 的 ofInt 和 ofFloat 函數(shù)的用法就講完了,大家可以看到 PropertyValuesHolder 使用起來(lái)也很容易,下面我們?cè)賮?lái)看看 PropertyValuesHolder 的 ofObject 的使用方法。 源碼在文章底部給出

3、PropertyValuesHolder 之 ofObject()

(1)、概述 我們先來(lái)看一下 ofObject 的構(gòu)造函數(shù)

public static PropertyValuesHolder ofObject(String propertyName, TypeEvaluator evaluator,Object... values)  
  • propertyName:ObjectAnimator 動(dòng)畫操作的屬性名;
  • evaluator:Evaluator 實(shí)例,Evaluator 是將當(dāng)前動(dòng)畫進(jìn)度計(jì)算出當(dāng)前值的類,可以使用系統(tǒng)自帶的 IntEvaluator、FloatEvaluator 也可以自定義,有關(guān) Evaluator 的知識(shí),大家可以參考《Animation 動(dòng)畫詳解(五)——ValueAnimator 高級(jí)進(jìn)階(一)》
  • values:可變長(zhǎng)參數(shù),表示操作動(dòng)畫屬性的值 它的各個(gè)參數(shù)與 ObjectAnimator.ofObject 的類似,只是少了 target 參數(shù)而已
public static ObjectAnimator ofObject(Object target, String propertyName,TypeEvaluator evaluator, Object... values) 

(2)、示例 下面我們就講講 PropertyValuesHolder.ofObject()函數(shù)的用法 本示例的效果圖如下:

http://wiki.jikexueyuan.com/project/android-animation/images/83.gif" alt="" />

這里實(shí)現(xiàn)的效果與《Animation 動(dòng)畫詳解(六)——ValueAnimator 高級(jí)進(jìn)階(二)》實(shí)現(xiàn)的效果相同,即通過(guò)自字義的 CharEvaluator 來(lái)自動(dòng)實(shí)現(xiàn)字母的改變與計(jì)算。 首先是自定義一個(gè) CharEvaluator,通過(guò)進(jìn)度值來(lái)自動(dòng)計(jì)算出當(dāng)前的字母:

public class CharEvaluator implements TypeEvaluator<Character> {  
    @Override  
    public Character evaluate(float fraction, Character startValue, Character endValue) {  
        int startInt  = (int)startValue;  
        int endInt = (int)endValue;  
        int curInt = (int)(startInt + fraction *(endInt - startInt));  
        char result = (char)curInt;  
        return result;  
    }  
} 

有關(guān)數(shù)字與字符間轉(zhuǎn)換的原理已經(jīng)在《Animation 動(dòng)畫詳解(六)——ValueAnimator 高級(jí)進(jìn)階(二)》講述,就不再細(xì)講。這個(gè) CharEvaluator 也是直接從這篇文章中拿過(guò)來(lái)的,強(qiáng)烈建議大家對(duì)這個(gè)系列文章從頭開(kāi)始看。 從 CharEvaluator 中可以看出,從 CharEvaluator 中產(chǎn)出的動(dòng)畫中間值類型為 Character 類型。TextView 中雖然有 setText(CharSequence text) 函數(shù),但這個(gè)函數(shù)的參數(shù)類型是 CharSequence,而不是 Character 類型。所以我們要自定義一個(gè)類派生自 TextView 來(lái)改變 TextView 的字符

public class MyTextView extends TextView {  
    public MyTextView(Context context, AttributeSet attrs) {  
        super(context, attrs);  
    }  
    public void setCharText(Character character){  
        setText(String.valueOf(character));  
    }  
} 

在這里,我們定義了一個(gè)方法 setCharText(Character character),參數(shù)就是 Character 類型,我們知道這個(gè)方法所對(duì)應(yīng)的屬性是 CharText; 最后 MyActivity,在點(diǎn)擊按鈕的時(shí)候開(kāi)始動(dòng)畫,核心代碼為:

public class MyActivity extends Activity {  
    private Button btn;  
    private TextView mTextView;  
    private MyTextView mMyTv;  
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  

        mMyTv = (MyTextView)findViewById(R.id.mytv);  
        btn = (Button) findViewById(R.id.btn);  
        btn.setOnClickListener(new View.OnClickListener() {  
            @Override  
            public void onClick(View v) {  
                doOfObjectAnim();  
            }  
        });  
    }  

    private void doOfObjectAnim(){  
        PropertyValuesHolder charHolder = PropertyValuesHolder.ofObject("CharText",new CharEvaluator(),new Character('A'),new Character('Z'));  
        ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(mMyTv, charHolder);  
        animator.setDuration(3000);  
        animator.setInterpolator(new AccelerateInterpolator());  
        animator.start();  
    }  
} 

這部分代碼,很好理解,在點(diǎn)擊按鈕的時(shí)候執(zhí)行 doOfObjectAnim()方法:

PropertyValuesHolder charHolder = PropertyValuesHolder.ofObject("CharText",new CharEvaluator(),new Character('A'),new Character('Z'));  
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(mMyTv, charHolder);  
animator.setDuration(3000);  
animator.setInterpolator(new AccelerateInterpolator());  
animator.start();  

首先是根據(jù) PropertyValuesHolder.ofObject 生成一個(gè) PropertyValuesHolder 實(shí)例,注意它的屬性就是 CharText,所對(duì)應(yīng)的 set 函數(shù)就是 setCharText,由于 CharEvaluator 的中間值是 Character 類型,所以 CharText 屬性所對(duì)應(yīng)的完整的函數(shù)聲明為 setCharText(Character character);這也就是我們?yōu)槭裁匆远x一個(gè) MyTextView 原因,就是因?yàn)?TextView 中沒(méi)有 setText(Character character)這樣的函數(shù)。 然后就是利用 ObjectAnimator.ofPropertyValuesHolder 生成 ObjectAnimator 實(shí)例了,最后就是對(duì) animator 設(shè)置并 start 了,沒(méi)什么難度,就不再講了。 源碼在文章底部給出 下面就開(kāi)始最重要的部分了,有關(guān) KeyFrame 的知識(shí)。

二、Keyframe

1、概述

通過(guò)前面幾篇的講解,我們知道如果要控制動(dòng)畫速率的變化,我們可以通過(guò)自定義插值器,也可以通過(guò)自定義 Evaluator 來(lái)實(shí)現(xiàn)。但如果真的讓我們?yōu)榱怂俾首兓Ч远x插值器或者 Evaluator 的話,恐怕大部分同學(xué)會(huì)有一萬(wàn)頭草泥馬在眼前奔過(guò),因?yàn)榇蟛糠值耐瑢W(xué)的數(shù)學(xué)知識(shí)已經(jīng)還給老師了。 為了解決方便的控制動(dòng)畫速率的問(wèn)題,谷歌為了我等屁民定義了一個(gè) KeyFrame 的類,KeyFrame 直譯過(guò)來(lái)就是關(guān)鍵幀。 關(guān)鍵幀這個(gè)概念是從動(dòng)畫里學(xué)來(lái)的,我們知道視頻里,一秒要播放 24 幀圖片,對(duì)于制作 flash 動(dòng)畫的同學(xué)來(lái)講,是不是每一幀都要畫出來(lái)呢?當(dāng)然不是了,如果每一幀都畫出來(lái),那估計(jì)做出來(lái)一個(gè)動(dòng)畫片都得要一年時(shí)間;比如我們要讓一個(gè)球在 30 秒時(shí)間內(nèi),從(0,0)點(diǎn)運(yùn)動(dòng)到(300,200)點(diǎn),那 flash 是怎么來(lái)做的呢,在 flash 中,我們只需要定義兩個(gè)關(guān)鍵幀,在動(dòng)畫開(kāi)始時(shí)定義一個(gè),把球的位置放在(0,0)點(diǎn);在 30 秒后,再定義一個(gè)關(guān)鍵幀,把球的位置放在(300,200)點(diǎn)。在動(dòng)畫 開(kāi)始時(shí),球初始在是(0,0)點(diǎn),30 秒時(shí)間內(nèi)就 adobe flash 就會(huì)自動(dòng)填充,把球平滑移動(dòng)到第二個(gè)關(guān)鍵幀的位置(300,200)點(diǎn); 通過(guò)上面分析 flash 動(dòng)畫的制作原理,我們知道,一個(gè)關(guān)鍵幀必須包含兩個(gè)原素,第一時(shí)間點(diǎn),第二位置。即這個(gè)關(guān)鍵幀是表示的是某個(gè)物體在哪個(gè)時(shí)間點(diǎn)應(yīng)該在哪個(gè)位置上。 所以谷歌的 KeyFrame 也不例外,KeyFrame 的生成方式為:

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

上面生成了三個(gè) KeyFrame 對(duì)象,其中 KeyFrame 的 ofInt 函數(shù)的聲明為:

public static Keyframe ofFloat(float fraction, float value) 
  • fraction:表示當(dāng)前的顯示進(jìn)度,即從加速器中 getInterpolation()函數(shù)的返回值;
  • value:表示當(dāng)前應(yīng)該在的位置 比如 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; 在理解了 KeyFrame.ofFloat()的參數(shù)以后,我們來(lái)看看 PropertyValuesHolder 是如何使用 KeyFrame 對(duì)象的:
public static PropertyValuesHolder ofKeyframe(String propertyName, Keyframe... values)
  • propertyName:動(dòng)畫所要操作的屬性名
  • values:Keyframe 的列表,PropertyValuesHolder 會(huì)根據(jù)每個(gè) Keyframe 的設(shè)定,定時(shí)將指定的值輸出給動(dòng)畫。

所以完整的 KeyFrame 的使用代碼應(yīng)該是這樣的:

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

第一步:生成 Keyframe 對(duì)象; 第二步:利用 PropertyValuesHolder.ofKeyframe()生成 PropertyValuesHolder 對(duì)象 第三步:ObjectAnimator.ofPropertyValuesHolder()生成對(duì)應(yīng)的 Animator

2、示例

在了解了 Keyframe 如何使用以后,下面我們就來(lái)用一個(gè)例子來(lái)看看 Keyframe 的使用方法。 本例的效果圖如下:

http://wiki.jikexueyuan.com/project/android-animation/images/84.gif" alt="" />

看起來(lái)跟開(kāi)篇的一樣,仔細(xì)對(duì)比一下,還是有不同的,這里只是實(shí)現(xiàn)了左右震動(dòng),但并沒(méi)有放大效果。

(1)、main.xml 我們先來(lái)看看布局代碼,代碼很簡(jiǎn)單,一個(gè) btn,一個(gè) imageview

<?xml version="1.0" encoding="utf-8"?>  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
              android:orientation="vertical"  
              android:layout_width="fill_parent"  
              android:layout_height="fill_parent">  
    <Button  
            android:id="@+id/btn"  
            android:layout_width="wrap_content"  
            android:layout_height="wrap_content"  
            android:text="start anim"/>  

    <ImageView  
            android:id="@+id/img"  
            android:layout_width="150dp"  
            android:layout_height="wrap_content"  
            android:scaleType="fitCenter"  
            android:layout_gravity="center_horizontal"  
            android:src="@drawable/phone"/>  
</LinearLayout>

這段布局代碼沒(méi)什么難度,就不再講了,下面來(lái)看看 MyActivity 中的處理 (2)、MyActivity.java

public class MyActivity extends Activity {  
    private ImageView mImage;  
    private Button mBtn;  
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
        mImage = (ImageView)findViewById(R.id.img);  
        mBtn = (Button)findViewById(R.id.btn);  
        mBtn.setOnClickListener(new View.OnClickListener() {  
            @Override  
            public void onClick(View v) {  
                doOfFloatAnim();  
            }  
        });  
    }  

    private void doOfFloatAnim(){  
        Keyframe frame0 = Keyframe.ofFloat(0f, 0);  
        Keyframe frame1 = Keyframe.ofFloat(0.1f, -20f);  
        Keyframe frame2 = Keyframe.ofFloat(0.2f, 20f);  
        Keyframe frame3 = Keyframe.ofFloat(0.3f, -20f);  
        Keyframe frame4 = Keyframe.ofFloat(0.4f, 20f);  
        Keyframe frame5 = Keyframe.ofFloat(0.5f, -20f);  
        Keyframe frame6 = Keyframe.ofFloat(0.6f, 20f);  
        Keyframe frame7 = Keyframe.ofFloat(0.7f, -20f);  
        Keyframe frame8 = Keyframe.ofFloat(0.8f, 20f);  
        Keyframe frame9 = Keyframe.ofFloat(0.9f, -20f);  
        Keyframe frame10 = Keyframe.ofFloat(1, 0);  
        PropertyValuesHolder frameHolder = PropertyValuesHolder.ofKeyframe("rotation",frame0,frame1,frame2,frame3,frame4,frame5,frame6,frame7,frame8,frame9,frame10);  

        Animator animator = ObjectAnimator.ofPropertyValuesHolder(mImage,frameHolder);  
        animator.setDuration(1000);  
        animator.start();  
    }  
} 

這段代碼難度也不大,在點(diǎn)擊按鈕的時(shí)候,執(zhí)行 doOfFloatAnim()函數(shù),關(guān)鍵問(wèn)題在 doOfFloatAnim()上: 首先,我們定義了 11 個(gè) keyframe:

Keyframe frame0 = Keyframe.ofFloat(0f, 0);  
Keyframe frame1 = Keyframe.ofFloat(0.1f, -20f);  
Keyframe frame2 = Keyframe.ofFloat(0.2f, 20f);  
Keyframe frame3 = Keyframe.ofFloat(0.3f, -20f);  
Keyframe frame4 = Keyframe.ofFloat(0.4f, 20f);  
Keyframe frame5 = Keyframe.ofFloat(0.5f, -20f);  
Keyframe frame6 = Keyframe.ofFloat(0.6f, 20f);  
Keyframe frame7 = Keyframe.ofFloat(0.7f, -20f);  
Keyframe frame8 = Keyframe.ofFloat(0.8f, 20f);  
Keyframe frame9 = Keyframe.ofFloat(0.9f, -20f);  
Keyframe frame10 = Keyframe.ofFloat(1, 0);

在這些 keyframe 中,首先指定在開(kāi)始和結(jié)束時(shí),旋轉(zhuǎn)角度為 0,即恢復(fù)原樣:

Keyframe frame0 = Keyframe.ofFloat(0f, 0);  
Keyframe frame10 = Keyframe.ofFloat(1, 0);

然后在過(guò)程中,讓它左右旋轉(zhuǎn),比如在進(jìn)度為 0.2 時(shí),旋轉(zhuǎn)到左邊 20 度位置:

Keyframe frame1 = Keyframe.ofFloat(0.1f, -20f); 

然后在進(jìn)度為 0.3 時(shí),旋轉(zhuǎn)到右邊 20 度位置:

Keyframe frame3 = Keyframe.ofFloat(0.3f, -20f);  

其它類似。正是因?yàn)閬?lái)回左右的旋轉(zhuǎn),所以我們看起來(lái)就表現(xiàn)為在震動(dòng) 然后,根據(jù)這些 Keyframe 生成 PropertyValuesHolder 對(duì)象,指定操作的屬性為 rotation

PropertyValuesHolder frameHolder = PropertyValuesHolder.ofKeyframe("rotation",frame0,frame1,frame2,frame3,frame4,frame5,frame6,frame7,frame8,frame9,frame10);  

Animator animator = ObjectAnimator.ofPropertyValuesHolder(mImage,frameHolder);  
animator.setDuration(1000);  
animator.start(); 

最后,利用 ObjectAnimator.ofPropertyValuesHolder(mImage,frameHolder)生成 ObjectAnimator 對(duì)象,并開(kāi)始動(dòng)畫。 到這里想必大家已經(jīng)對(duì) Keyframe 有了初步的認(rèn)識(shí),下面我們就來(lái)詳細(xì)的講講 Keyframe; 源碼在文章底部給出

3、Keyframe 之 ofFloat、ofInt 與常用函數(shù)

(1)、ofFloat、ofInt 上面我們看到 Keyframe.ofFloat()函數(shù)的用法,其實(shí) Keyframe 除了 ofFloat()以外,還有 ofInt()、ofObject()這些創(chuàng)建 Keyframe 實(shí)例的方法,Keyframe.ofObject()我們下部分再講,這部分,我們著重看看 ofFloat 與 ofInt 的構(gòu)造函數(shù)與使用方法:

/** 
 * 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)  

由于 ofFloat 和 ofInt 的構(gòu)造函數(shù)都是一樣的,我們這里只以 ofFloat 來(lái)例來(lái)說(shuō)。 上面我們已經(jīng)講了 ofFloat(float fraction, float value)的用法,fraction 表示當(dāng)前關(guān)鍵幀所在的動(dòng)畫進(jìn)度位置,value 表示當(dāng)前位置所對(duì)應(yīng)的值。 而另一個(gè)構(gòu)造函數(shù):

public static Keyframe ofFloat(float fraction) 

這個(gè)構(gòu)造函數(shù)比較特殊,只有一個(gè)參數(shù) fraction,表示當(dāng)前關(guān)鍵幀所在的動(dòng)畫進(jìn)度位置。那在這個(gè)進(jìn)度時(shí)所對(duì)應(yīng)的值要怎么設(shè)置呢? 當(dāng)然有方法啦,除了上面的構(gòu)造函數(shù),Keyframe 還有一些常用函數(shù)來(lái)設(shè)置 fraction,value 和 interpolator,定義如下: (2)、常用函數(shù):

/** 
 * 設(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)  

這三個(gè)函數(shù)中,插值器的作用應(yīng)該是比較難理解,如果給這個(gè) Keyframe 設(shè)置上插值器,那么這個(gè)插值器就是從上一個(gè) Keyframe 開(kāi)始到當(dāng)前設(shè)置插值器的 Keyframe 時(shí),這個(gè)過(guò)程值的計(jì)算是利用這個(gè)插值器的,比如:

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

在上面的代碼中,我們給 frame1 設(shè)置了插值器 BounceInterpolator,那么在 frame0 到 frame1 的中間值計(jì)算過(guò)程中,就是用的就是回彈插值器; 同樣,我們給 frame2 設(shè)置了線性插值器(LinearInterpolator),所以在 frame1 到 frame2 的中間值計(jì)算過(guò)程中,使用的就是線性插值器 很顯然,給 Keyframe.ofFloat(0f, 0)設(shè)置插值器是無(wú)效的,因?yàn)樗堑谝粠?(3)、示例 1——沒(méi)有插值器 下面我們就舉個(gè)例子來(lái)看下,如何使用上面的各個(gè)函數(shù)的用法,同樣是基于上面的電話響鈴的例子,如果我們只保存三幀,代碼如下:

Keyframe frame0 = Keyframe.ofFloat(0f, 0);  
Keyframe frame1 = Keyframe.ofFloat(0.5f, 100f);  
Keyframe frame2 = Keyframe.ofFloat(1);  
frame2.setValue(0f);  
PropertyValuesHolder frameHolder = PropertyValuesHolder.ofKeyframe("rotation",frame0,frame1,frame2);  

Animator animator = ObjectAnimator.ofPropertyValuesHolder(mImage,frameHolder);  
animator.setDuration(3000);  
animator.start();  

在這段代碼中,總共就只有三個(gè)關(guān)鍵幀,最后一個(gè) Keyframe 的生成方法是利用:

Keyframe frame2 = Keyframe.ofFloat(1);  
frame2.setValue(0f);

對(duì)于 Keyframe 而言,fraction 和 value 這兩個(gè)參數(shù)是必須有的,所以無(wú)論用哪種方式實(shí)例化 Keyframe 都必須保證這兩個(gè)值必須被初始化。 這里沒(méi)有設(shè)置插值器,會(huì)使用默認(rèn)的線性插值器(LinearInterpolator) 效果圖如下:

http://wiki.jikexueyuan.com/project/android-animation/images/85.gif" alt="" />

(4)、示例 2——使用插值器 下面,我們給上面的代碼加上插值器,著重看一下,插值器在哪部分起做用

Keyframe frame0 = Keyframe.ofFloat(0f, 0);  
Keyframe frame1 = Keyframe.ofFloat(0.5f, 100f);  
Keyframe frame2 = Keyframe.ofFloat(1);  
frame2.setValue(0f);  
frame2.setInterpolator(new BounceInterpolator());  
PropertyValuesHolder frameHolder = PropertyValuesHolder.ofKeyframe("rotation",frame0,frame1,frame2);  

Animator animator = ObjectAnimator.ofPropertyValuesHolder(mImage,frameHolder);  
animator.setDuration(3000);  
animator.start();

我們給最后一幀 frame2 添加上回彈插值器(BounceInterpolator),然后看看效果:

http://wiki.jikexueyuan.com/project/android-animation/images/86.gif" alt="" />

從效果圖中可以看出,在 frame1 到 frame2 的過(guò)程中,使用了回彈插值器,所以從這里也可驗(yàn)證我們上面的論述:如果給當(dāng)前幀添加插值器,那么在上一幀到當(dāng)前幀的進(jìn)度值計(jì)算過(guò)程中會(huì)使用這個(gè)插值器。 好了,到這里有關(guān) ofInt,ofFloat 和常用的幾個(gè)函數(shù)的講解就結(jié)束了,下面我們?cè)賮?lái)看看 ofObject 的使用方法。

源碼在文章底部給出

4、Keyframe 之 ofObject

與 ofInt,ofFloat 一樣,ofObject 也有兩個(gè)構(gòu)造函數(shù):

public static Keyframe ofObject(float fraction)  
public static Keyframe ofObject(float fraction, Object value)

同樣,如果使用 ofObject(float fraction)來(lái)構(gòu)造,也必須使用 setValue(Object value)來(lái)設(shè)置這個(gè)關(guān)鍵幀所對(duì)應(yīng)的值。 我們還以 TextView 更改字母的例子來(lái)使用下 Keyframe.ofObject 效果圖如下:

http://wiki.jikexueyuan.com/project/android-animation/images/87.gif" alt="" />

明顯 L 前的 12 個(gè)字母變化的特別快,后面的 14 個(gè)字母變化的比較慢。 我們使用到的 MyTextView,CharEvaluator 都與上面的一樣,只是動(dòng)畫部分不同,這里只列出動(dòng)畫的代碼:

Keyframe frame0 = Keyframe.ofObject(0f, new Character('A'));  
Keyframe frame1 = Keyframe.ofObject(0.1f, new Character('L'));  
Keyframe frame2 = Keyframe.ofObject(1,new Character('Z'));  

PropertyValuesHolder frameHolder = PropertyValuesHolder.ofKeyframe("CharText",frame0,frame1,frame2);  
frameHolder.setEvaluator(new CharEvaluator());  
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(mMyTv,frameHolder);  
animator.setDuration(3000);  
animator.start();  

在這個(gè)動(dòng)畫中,我們定義了三幀:

Keyframe frame0 = Keyframe.ofObject(0f, new Character('A'));  
Keyframe frame1 = Keyframe.ofObject(0.1f, new Character('L'));  
Keyframe frame2 = Keyframe.ofObject(1,new Character('Z'));  

frame0 表示在進(jìn)度為 0 的時(shí)候,動(dòng)畫的字符是 A;frame1 表示在進(jìn)度在 0.1 的時(shí)候,動(dòng)畫的字符是 L;frame2 表示在結(jié)束的時(shí)候,動(dòng)畫的字符是 Z; 利用關(guān)鍵幀創(chuàng)建 PropertyValuesHolder 后,一定要記得設(shè)置自定義的 Evaluator:

frameHolder.setEvaluator(new CharEvaluator()); 

凡是使用 ofObject 來(lái)做動(dòng)畫的時(shí)候,都必須調(diào)用 frameHolder.setEvaluator 顯示設(shè)置 Evaluator,因?yàn)橄到y(tǒng)根本是無(wú)法知道,你動(dòng)畫的中間值 Object 真正是什么類型的。 源碼在文章底部給出

5、疑問(wèn):如果沒(méi)有設(shè)置進(jìn)度為 0 或者進(jìn)度為 1 時(shí)的關(guān)鍵幀,展示是怎樣的?

首先,我們以下面這個(gè)動(dòng)畫為例:

Keyframe frame0 = Keyframe.ofFloat(0f, 0);  
Keyframe frame1 = Keyframe.ofFloat(0.5f, 100f);  
Keyframe frame2 = Keyframe.ofFloat(1,0);  
PropertyValuesHolder frameHolder = PropertyValuesHolder.ofKeyframe("rotation", frame0,frame1,frame2);  

Animator animator = ObjectAnimator.ofPropertyValuesHolder(mImage, frameHolder);  
animator.setDuration(3000);  
animator.start(); 

這里有三個(gè)幀,在進(jìn)度為 0.5 時(shí),電話向右旋轉(zhuǎn) 100 度,然后再轉(zhuǎn)回來(lái)。 效果圖如下:

http://wiki.jikexueyuan.com/project/android-animation/images/88.gif" alt="" />

嘗試一:去掉第 0 幀,將以第一幀為起始位置 如果我們把第 0 幀去掉,只保留中間幀和結(jié)束幀,看結(jié)果會(huì)怎樣

Keyframe frame1 = Keyframe.ofFloat(0.5f, 100f);  
Keyframe frame2 = Keyframe.ofFloat(1,0);  
PropertyValuesHolder frameHolder = PropertyValuesHolder.ofKeyframe("rotation",frame1,frame2);  

Animator animator = ObjectAnimator.ofPropertyValuesHolder(mImage, frameHolder);  
animator.setDuration(3000);  
animator.start(); 

效果圖如下:

http://wiki.jikexueyuan.com/project/android-animation/images/89.gif" alt="" />

可以看到,動(dòng)畫是直接從中間幀 frame1 開(kāi)始的,即當(dāng)沒(méi)有第 0 幀時(shí),動(dòng)畫從最近的一個(gè)幀開(kāi)始。

嘗試二:去掉結(jié)束幀,將最后一幀為結(jié)束幀 如果我們把結(jié)束幀去掉,保留第 0 幀和中間幀,看結(jié)果會(huì)怎樣:

Keyframe frame0 = Keyframe.ofFloat(0f, 0);  
Keyframe frame1 = Keyframe.ofFloat(0.5f, 100f);  
PropertyValuesHolder frameHolder = PropertyValuesHolder.ofKeyframe("rotation", frame0,frame1);  

Animator animator = ObjectAnimator.ofPropertyValuesHolder(mImage, frameHolder);  
animator.setDuration(3000);  
animator.start();

效果圖如下:

http://wiki.jikexueyuan.com/project/android-animation/images/90.gif" alt="" />

嘗試三:只保留一個(gè)中間幀,會(huì)崩 如果我們把第 0 幀和結(jié)束幀去掉,代碼如下:

PropertyValuesHolder frameHolder = PropertyValuesHolder.ofKeyframe("rotation",frame1);  

Animator animator = ObjectAnimator.ofPropertyValuesHolder(mImage, frameHolder);  
animator.setDuration(3000);  
animator.start(); 

在點(diǎn)擊按鈕開(kāi)始動(dòng)畫時(shí),就直接崩了,報(bào)錯(cuò)信息如下:

http://wiki.jikexueyuan.com/project/android-animation/images/17.png" alt="" />

報(bào)錯(cuò)問(wèn)題是數(shù)組越界,也就是說(shuō),至少要有兩個(gè)幀才行。

嘗試四:保留兩個(gè)中間幀 再嘗試一下,如果我們把第 0 幀和結(jié)束幀去掉,保留兩個(gè)中間幀會(huì)怎樣: 我們?cè)谏厦娲a上再加一個(gè)中間幀:

Keyframe frame1 = Keyframe.ofFloat(0.5f, 100f);  
Keyframe frame2 = Keyframe.ofFloat(0.7f,50f);  
PropertyValuesHolder frameHolder = PropertyValuesHolder.ofKeyframe("rotation",frame1,frame2);  

Animator animator = ObjectAnimator.ofPropertyValuesHolder(mImage, frameHolder);  
animator.setDuration(3000);  
animator.start();

效果圖如下:

http://wiki.jikexueyuan.com/project/android-animation/images/91.gif" alt="" />

可以看到,在保留兩個(gè)幀的情況下,是可以運(yùn)行的,而且,由于去掉了第 0 幀,所以將 frame1 做為起始幀,又由于去掉了結(jié)束幀,所以將 frame2 做為結(jié)束幀。 下面我們做出結(jié)論:

  • 如果去掉第 0 幀,將以第一個(gè)關(guān)鍵幀為起始位置
  • 如果去掉結(jié)束幀,將以最后一個(gè)關(guān)鍵幀為結(jié)束位置
  • 使用 Keyframe 來(lái)構(gòu)建動(dòng)畫,至少要有兩個(gè)或兩個(gè)以上幀

6、開(kāi)篇的電話響鈴效果

再重新看看開(kāi)篇的電話響鈴的效果圖:

http://wiki.jikexueyuan.com/project/android-animation/images/92.gif" alt="" />

發(fā)現(xiàn)了沒(méi),除了左右震動(dòng),圖標(biāo)在震動(dòng)過(guò)程中始終是放大的。 上面,我們已經(jīng)實(shí)現(xiàn)了左右震動(dòng),下面我們?cè)偬砑臃糯笮Ч秃昧恕?框架的部分就不再講了,與上面一樣,只是動(dòng)畫部分不同,先貼出動(dòng)畫的完整代碼:

/** 
 * 左右震動(dòng)效果 
 */  
Keyframe frame0 = Keyframe.ofFloat(0f, 0);  
Keyframe frame1 = Keyframe.ofFloat(0.1f, -20f);  
Keyframe frame2 = Keyframe.ofFloat(0.2f, 20f);  
Keyframe frame3 = Keyframe.ofFloat(0.3f, -20f);  
Keyframe frame4 = Keyframe.ofFloat(0.4f, 20f);  
Keyframe frame5 = Keyframe.ofFloat(0.5f, -20f);  
Keyframe frame6 = Keyframe.ofFloat(0.6f, 20f);  
Keyframe frame7 = Keyframe.ofFloat(0.7f, -20f);  
Keyframe frame8 = Keyframe.ofFloat(0.8f, 20f);  
Keyframe frame9 = Keyframe.ofFloat(0.9f, -20f);  
Keyframe frame10 = Keyframe.ofFloat(1, 0);  
PropertyValuesHolder frameHolder1 = PropertyValuesHolder.ofKeyframe("rotation", frame0, frame1, frame2, frame3, frame4,frame5, frame6, frame7, frame8, frame9, frame10);  

/** 
 * scaleX 放大 1.1 倍 
 */  
Keyframe scaleXframe0 = Keyframe.ofFloat(0f, 1);  
Keyframe scaleXframe1 = Keyframe.ofFloat(0.1f, 1.1f);  
Keyframe scaleXframe2 = Keyframe.ofFloat(0.2f, 1.1f);  
Keyframe scaleXframe3 = Keyframe.ofFloat(0.3f, 1.1f);  
Keyframe scaleXframe4 = Keyframe.ofFloat(0.4f, 1.1f);  
Keyframe scaleXframe5 = Keyframe.ofFloat(0.5f, 1.1f);  
Keyframe scaleXframe6 = Keyframe.ofFloat(0.6f, 1.1f);  
Keyframe scaleXframe7 = Keyframe.ofFloat(0.7f, 1.1f);  
Keyframe scaleXframe8 = Keyframe.ofFloat(0.8f, 1.1f);  
Keyframe scaleXframe9 = Keyframe.ofFloat(0.9f, 1.1f);  
Keyframe scaleXframe10 = Keyframe.ofFloat(1, 1);  
PropertyValuesHolder frameHolder2 = PropertyValuesHolder.ofKeyframe("ScaleX",scaleXframe0,scaleXframe1,scaleXframe2,scaleXframe3,scaleXframe4,scaleXframe5,scaleXframe6,scaleXframe7,scaleXframe8,scaleXframe9,scaleXframe10);  

/** 
 * scaleY 放大 1.1 倍 
 */  
Keyframe scaleYframe0 = Keyframe.ofFloat(0f, 1);  
Keyframe scaleYframe1 = Keyframe.ofFloat(0.1f, 1.1f);  
Keyframe scaleYframe2 = Keyframe.ofFloat(0.2f, 1.1f);  
Keyframe scaleYframe3 = Keyframe.ofFloat(0.3f, 1.1f);  
Keyframe scaleYframe4 = Keyframe.ofFloat(0.4f, 1.1f);  
Keyframe scaleYframe5 = Keyframe.ofFloat(0.5f, 1.1f);  
Keyframe scaleYframe6 = Keyframe.ofFloat(0.6f, 1.1f);  
Keyframe scaleYframe7 = Keyframe.ofFloat(0.7f, 1.1f);  
Keyframe scaleYframe8 = Keyframe.ofFloat(0.8f, 1.1f);  
Keyframe scaleYframe9 = Keyframe.ofFloat(0.9f, 1.1f);  
Keyframe scaleYframe10 = Keyframe.ofFloat(1, 1);  
PropertyValuesHolder frameHolder3 = PropertyValuesHolder.ofKeyframe("ScaleY",scaleYframe0,scaleYframe1,scaleYframe2,scaleYframe3,scaleYframe4,scaleYframe5,scaleYframe6,scaleYframe7,scaleYframe8,scaleYframe9,scaleYframe10);  

/** 
 * 構(gòu)建動(dòng)畫 
 */  
Animator animator = ObjectAnimator.ofPropertyValuesHolder(mImage, frameHolder1,frameHolder2,frameHolder3);  
animator.setDuration(1000);  
animator.start();

這里的總共分為四步: 第一步,實(shí)現(xiàn)左右震鈴效果; 這部分代碼前面已經(jīng)講過(guò),這里就不再贅述 第二步,利用 View 類中的 SetScaleX(float value)方法所對(duì)應(yīng)的 ScaleX 屬性,在動(dòng)畫過(guò)程中,將圖片橫向放大 1.1 倍:

Keyframe scaleXframe0 = Keyframe.ofFloat(0f, 1);  
Keyframe scaleXframe1 = Keyframe.ofFloat(0.1f, 1.1f);  
Keyframe scaleXframe2 = Keyframe.ofFloat(0.2f, 1.1f);  
Keyframe scaleXframe3 = Keyframe.ofFloat(0.3f, 1.1f);  
Keyframe scaleXframe4 = Keyframe.ofFloat(0.4f, 1.1f);  
Keyframe scaleXframe5 = Keyframe.ofFloat(0.5f, 1.1f);  
Keyframe scaleXframe6 = Keyframe.ofFloat(0.6f, 1.1f);  
Keyframe scaleXframe7 = Keyframe.ofFloat(0.7f, 1.1f);  
Keyframe scaleXframe8 = Keyframe.ofFloat(0.8f, 1.1f);  
Keyframe scaleXframe9 = Keyframe.ofFloat(0.9f, 1.1f);  
Keyframe scaleXframe10 = Keyframe.ofFloat(1, 1);

非常注意的是,在動(dòng)畫過(guò)程中放大 1.1 倍,在開(kāi)始動(dòng)畫和動(dòng)畫結(jié)束時(shí),都要還原狀態(tài),即原大小的 1 倍值:

Keyframe scaleXframe0 = Keyframe.ofFloat(0f, 1);  
Keyframe scaleXframe10 = Keyframe.ofFloat(1, 1);  

第三步,同樣利用 View 類的 SetScaleY(float value)方法,在動(dòng)畫過(guò)程中將圖片縱向放大 1.1 倍。原理與 scaleX 相同,就不再細(xì)講。 第四步:生成 ObjectAnimator 實(shí)例:

Animator animator = ObjectAnimator.ofPropertyValuesHolder(mImage, frameHolder1,frameHolder2,frameHolder3);  

我們前面講過(guò),ObjectAnimator ofPropertyValuesHolder(Object target,PropertyValuesHolder… values)中第二個(gè)參數(shù)是可變長(zhǎng)參數(shù),可以傳進(jìn)去任何多個(gè) PropertyValuesHolder 對(duì)象,這些對(duì)象所對(duì)應(yīng)的動(dòng)畫會(huì)同時(shí)作用于控件上。這里我們就將三個(gè)屬性動(dòng)畫同時(shí)作用在 mImage 上,所以圖片的動(dòng)畫就表現(xiàn)為在左右震動(dòng)的同時(shí),橫向放大 1.1 倍,縱向也放大了 1.1 倍。 所以說(shuō),借助 Keyframe,不需要使用 AnimatorSet,也能實(shí)現(xiàn)多個(gè)動(dòng)畫同時(shí)播放。這也是 ObjectAnimator 中唯一一個(gè)能實(shí)現(xiàn)多動(dòng)畫同時(shí)播放的方法,其它的 ObjectAnimator.ofInt,ObjectAnimator.ofFloat,ObjectAnimator.ofObject 都只能實(shí)現(xiàn)針對(duì)一個(gè)屬性動(dòng)畫的操作! 源碼在文章底部給出

三、PropertyValuesHolder 之其它函數(shù)

PropertyValuesHolder 除了上面的講到的 ofInt,ofFloat,ofObject,ofKeyframe 以外,api 11 的還有幾個(gè)函數(shù):

/** 
 * 設(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) 

這些函數(shù)都比較好理解,setFloatValues(float… values)對(duì)應(yīng) PropertyValuesHolder.ofFloat(),用于動(dòng)態(tài)設(shè)置動(dòng)畫中的數(shù)值。setIntValues、setKeyframes、setObjectValues 同理; setPropertyName 用于設(shè)置 PropertyValuesHolder 所需要操作的動(dòng)畫屬性名; 最重要的是 setEvaluator(TypeEvaluator evaluator)

/** 
 * 設(shè)置動(dòng)畫的 Evaluator 
 */  
public void setEvaluator(TypeEvaluator evaluator)

如果是利用 PropertyValuesHolder.ofObject()來(lái)創(chuàng)建動(dòng)畫實(shí)例的話,我們是一定要顯示調(diào)用 PropertyValuesHolder.setEvaluator()來(lái)設(shè)置 Evaluator 的。在上面的字母轉(zhuǎn)換的例子中,我們已經(jīng)用過(guò)這個(gè)函數(shù)了。這里也就沒(méi)什么好講的了。

好了,這篇文章到這里就結(jié)束了,這篇文章真的太!長(zhǎng)!了……大家耐心看看吧,必須 Keyframe 的知識(shí)還是很必須的。

源碼內(nèi)容:

1、《BlogPropertyValuesHolder》:第一部分 PropertyValuesHolder 所對(duì)應(yīng)源碼 2、《BlogKeyframe》:第三部分 Keyframe 所對(duì)應(yīng)源碼

如果本文有幫到你,記得加關(guān)注哦

源碼下載地址:

CSDN:http://download.csdn.net/detail/harvic880925/9445780 github:https://github.com/harvic/BlogResForGitHub 請(qǐng)大家尊重原創(chuàng)者版權(quán),轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/harvic880925/article/details/50752838 謝謝