在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

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

ObjectAnimator 基本使用

一、概述

1、引入

上幾篇給大家講了 ValueAnimator,但 ValueAnimator 有個缺點,就是只能對數(shù)值對動畫計算。我們要想對哪個控件操作,需要監(jiān)聽動畫過程,在監(jiān)聽中對控件操作。這樣使用起來相比補間動畫而言就相對比較麻煩。 為了能讓動畫直接與對應(yīng)控件相關(guān)聯(lián),以使我們從監(jiān)聽動畫過程中解放出來,谷歌的開發(fā)人員在 ValueAnimator 的基礎(chǔ)上,又派生了一個類 ObjectAnimator; 由于 ObjectAnimator 是派生自 ValueAnimator 的,所以 ValueAnimator 中所能使用的方法,在 ObjectAnimator 中都可以正常使用。 但 ObjectAnimator 也重寫了幾個方法,比如 ofInt(),ofFloat()等。我們先看看利用 ObjectAnimator 重寫的 ofFloat 方法如何實現(xiàn)一個動畫:(改變透明度)

ObjectAnimator animator = ObjectAnimator.ofFloat(tv,"alpha",1,0,1);  
animator.setDuration(2000);  
animator.start(); 

效果圖如下:

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

我們這里還是直接使用上一篇的框架代碼;(當(dāng)點擊 start anim 時執(zhí)行動畫)從上面的代碼中可以看到構(gòu)造 ObjectAnimator 的方法非常簡單:

public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) 
  • 第一個參數(shù)用于指定這個動畫要操作的是哪個控件
  • 第二個參數(shù)用于指定這個動畫要操作這個控件的哪個屬性
  • 第三個參數(shù)是可變長參數(shù),這個就跟 ValueAnimator 中的可變長參數(shù)的意義一樣了,就是指這個屬性值是從哪變到哪。像我們上面的代碼中指定的就是將 textview 的 alpha 屬性從 0 變到 1 再變到 0; 下面我們再來看一下如何實現(xiàn)旋轉(zhuǎn)效果:
ObjectAnimator animator = ObjectAnimator.ofFloat(tv,"rotation",0,180,0);  
animator.setDuration(2000);  
animator.start();

效果圖如下:

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

從代碼中可以看到,我們只需要改變 ofFloat()的第二個參數(shù)的值就可以實現(xiàn)對應(yīng)的動畫; 那么問題來了,我們怎么知道第二個參數(shù)的值是啥呢?

2、setter 函數(shù)

我們再回來看構(gòu)造改變 rotation 值的 ObjectAnimator 的方法

ObjectAnimator animator = ObjectAnimator.ofFloat(tv,"rotation",0,180,0);

TextView 控件有 rotation 這個屬性嗎?沒有,不光 TextView 沒有,連它的父類 View 中也沒有這個屬性。那它是怎么來改變這個值的呢?其實,ObjectAnimator 做動畫,并不是根據(jù)控件 xml 中的屬性來改變的,而是通過指定屬性所對應(yīng)的 set 方法來改變的。比如,我們上面指定的改變 rotation 的屬性值,ObjectAnimator 在做動畫時就會到指定控件(TextView)中去找對應(yīng)的 setRotation()方法來改變控件中對應(yīng)的值。同樣的道理,當(dāng)我們在最開始的示例代碼中,指定改變”alpha”屬性值的時候,ObjectAnimator 也會到 TextView 中去找對應(yīng)的 setAlpha()方法。那 TextView 中都有這些方法嗎,有的,這些方法都是從 View 中繼承過來的,在 View 中有關(guān)動畫,總共有下面幾組 set 方法:

//1、透明度:alpha  
public void setAlpha(float alpha)  

//2、旋轉(zhuǎn)度數(shù):rotation、rotationX、rotationY  
public void setRotation(float rotation)  
public void setRotationX(float rotationX)  
public void setRotationY(float rotationY)  

//3、平移:translationX、translationY  
public void setTranslationX(float translationX)   
public void setTranslationY(float translationY)  

//縮放:scaleX、scaleY  
public void setScaleX(float scaleX)  
public void setScaleY(float scaleY) 

可以看到在 View 中已經(jīng)實現(xiàn)了有關(guān) alpha,rotaion,translate,scale 相關(guān)的 set 方法。所以我們在構(gòu)造 ObjectAnimator 時可以直接使用。 在開始逐個看這些函數(shù)的使用方法前,我們先做一個總結(jié): 1、要使用 ObjectAnimator 來構(gòu)造對畫,要操作的控件中,必須存在對應(yīng)的屬性的 set 方法 2、setter 方法的命名必須以駱駝拼寫法命名,即 set 后每個單詞首字母大寫,其余字母小寫,即類似于 setPropertyName 所對應(yīng)的屬性為 propertyName 下面我們就來看一下上面中各個方法的使用方法及作用。 有關(guān) alpha 的用法,上面已經(jīng)講過了,下面我們來看看其它的

(1)、setRotationX、setRotationY 與 setRotation

  • setRotationX(float rotationX):表示圍繞 X 軸旋轉(zhuǎn),rotationX 表示旋轉(zhuǎn)度數(shù)
  • setRotationY(rotationY):表示圍繞 Y 軸旋轉(zhuǎn),rotationY 表示旋轉(zhuǎn)度數(shù)
  • setRotation(float rotation):表示圍繞 Z 旋轉(zhuǎn),rotation 表示旋轉(zhuǎn)度數(shù)

先來看看 setRotationX 的效果:

ObjectAnimator animator = ObjectAnimator.ofFloat(tv,"rotationX",0,270,0);  
animator.setDuration(2000);  
animator.start();

效果圖如下:

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

從效果圖中明顯看出,textview 的旋轉(zhuǎn)方法是圍繞 X 軸旋轉(zhuǎn)的,我們設(shè)定為從 0 度旋轉(zhuǎn)到 270 度再返回 0 度。 然后再來看看 setRotationY 的使用方法與效果:

ObjectAnimator animator = ObjectAnimator.ofFloat(tv,"rotationY",0,180,0);  
animator.setDuration(2000);  
animator.start();

效果圖如下:

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

從效果圖中明顯可以看出圍繞 Y 軸旋轉(zhuǎn)的。 我們再來看看 setRotation 的用法與效果:

ObjectAnimator animator = ObjectAnimator.ofFloat(tv,"rotation",0,270,0);  
animator.setDuration(2000);  
animator.start();  

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

我們上面說了,setRotation 是圍繞 Z 軸旋轉(zhuǎn)的,可能有些同學(xué)不理解什么是 Z 軸,我們來看一張圖:

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

從這張圖中,綠色框部分表示手機屏幕,很明顯可以看出 Z 軸就是從屏幕左上角原點向外伸出的一條軸。這樣,我們也就可以理解圍繞 Z 軸旋轉(zhuǎn),為什么是這樣子轉(zhuǎn)了。

(2)、setTranslationX 與 setTranslationY

  • setTranslationX(float translationX) :表示在 X 軸上的平移距離,以當(dāng)前控件為原點,向右為正方向,參數(shù) translationX 表示移動的距離。
  • setTranslationY(float translationY) :表示在 Y 軸上的平移距離,以當(dāng)前控件為原點,向下為正方向,參數(shù) translationY 表示移動的距離。 我們先看看 setTranslationX 的用法:
ObjectAnimator animator = ObjectAnimator.ofFloat(tv, "translationX", 0, 200, -200,0);  
animator.setDuration(2000);  
animator.start();  

效果圖如下:

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

所以,我們上面在構(gòu)造動畫時,指定的移動距離是(0, 200, -200,0),所以控件會從自身所有位置向右移動 200 像素,然后再移動到距離原點-200 的位置,最后回到原點; 然后我們來看看 setTranslateY 的用法:

ObjectAnimator animator = ObjectAnimator.ofFloat(tv, "translationY", 0, 200, -100,0);  
animator.setDuration(2000);  
animator.start(); 

效果圖如下:(為了方便看到效果,將 textview 垂直居中)

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

同樣,移動位置的坐標也都是以當(dāng)前控件所在位置為中心點的。所以對應(yīng)的移動位置從原點移動向下移動 200 像素,然后再移動到向下到距原點 200 像素的位置,最后再回到(0,0)從效果圖中很明顯可以看出來。 從上面可以看出:每次移動距離的計算都是以原點為中心的;比如初始動畫為 ObjectAnimator.ofFloat(tv, “translationY”, 0, 200, -100,0)表示首先從 0 移動到正方向 200 的位置,然后再移動到負方向 100 的位置,最后移動到原點。

(3)、setScaleX 與 setScaleY

  • setScaleX(float scaleX):在 X 軸上縮放,scaleX 表示縮放倍數(shù)
  • setScaleY(float scaleY):在 Y 軸上縮放,scaleY 表示縮放倍數(shù) 我們來看看 setScaleX 的用法:
ObjectAnimator animator = ObjectAnimator.ofFloat(tv, "scaleX", 0, 3, 1);  
animator.setDuration(2000);  
animator.start();

效果圖如下:

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

在效果圖中,從 0 倍放大到 3 倍,然后再還原到 1 倍的原始狀態(tài)。 然后再來看看 setScaleY 的用法

ObjectAnimator animator = ObjectAnimator.ofFloat(tv, "scaleY", 0, 3, 1);  
animator.setDuration(2000);  
animator.start(); 

為了更好的看到效果,我把 textview 垂直居中了,效果圖如下:

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

源碼在文章底部給出 好了,到這里有關(guān) View 中自帶的 set 函數(shù)講完了,我們來看看 ObjectAnimator 是如何實現(xiàn)控件動畫效果的。

3、ObjectAnimator 動畫原理

我們先來看張圖:

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

在這張圖中,將 ValueAnimator 的動畫流程與 ObjectAnimator 的動畫流程做了個對比。 可以看到 ObjectAnimator 的動畫流程中,也是首先通過加速器產(chǎn)生當(dāng)前進度的百分比,然后再經(jīng)過 Evaluator 生成對應(yīng)百分比所對應(yīng)的數(shù)字值。這兩步與 ValueAnimator 是完全一樣的,唯一不同的是最后一步,在 ValueAnimator 中,我們要通過添加監(jiān)聽器來監(jiān)聽當(dāng)前數(shù)字值。而在 ObjectAnimator 中,則是先根據(jù)屬性值拼裝成對應(yīng)的 set 函數(shù)的名字,比如這里的 scaleY 的拼裝方法就是將屬性的第一個字母強制大寫后,與 set 拼接,所以就是 setScaleY。然后通過反射找到對應(yīng)控件的 setScaleY(float scaleY)函數(shù),將當(dāng)前數(shù)字值做為 setScaleY(float scale)的參數(shù)將其傳入。 這里在找到控件的 set 函數(shù)以后,是通過反射來調(diào)用這個函數(shù)的,有關(guān)反射的使用大家可以參考《夯實 JAVA 基本之二 —— 反射(1):基本類周邊信息獲取》 這就是 ObjectAnimator 的流程,最后一步總結(jié)起來就是調(diào)用對應(yīng)屬性的 set 方法,將動畫當(dāng)前數(shù)字值做為參數(shù)傳進去。

根據(jù)上面的流程,這里有幾個注意事項: (1)、拼接 set 函數(shù)的方法:上面我們也說了是首先是強制將屬性的第一個字母大寫,然后與 set 拼接,就是對應(yīng)的 set 函數(shù)的名字。注意,只是強制將屬性的第一個字母大寫,后面的部分是保持不變的。反過來,如果我們的函數(shù)名命名為 setScalePointX(float ),那我們在寫屬性時可以寫成”scalePointX”或者寫成“ScalePointX”都是可以的,即第一個字母大小寫可以隨意,但后面的部分必須與 set 方法后的大小寫保持一致。 (2)、如何確定函數(shù)的參數(shù)類型:上面我們知道了如何找到對應(yīng)的函數(shù)名,那對應(yīng)的參數(shù)方法的參數(shù)類型如何確定呢?我們在講 ValueAnimator 的時候說過,動畫過程中產(chǎn)生的數(shù)字值與構(gòu)造時傳入的值類型是一樣的。由于 ObjectAnimator 與 ValueAnimator 在插值器和 Evaluator 這兩步是完全一樣的,而當(dāng)前動畫數(shù)值的產(chǎn)生是在 Evaluator 這一步產(chǎn)生的,所以 ObjectAnimator 的動畫中產(chǎn)生的數(shù)值類型也是與構(gòu)造時的類型一樣的。那么問題來了,像我們的構(gòu)造方法。

ObjectAnimator animator = ObjectAnimator.ofFloat(tv, "scaleY", 0, 3, 1);

由于構(gòu)造時使用的是 ofFloat 函數(shù),所以中間值的類型應(yīng)該是 Float 類型的,所以在最后一步拼裝出來的 set 函數(shù)應(yīng)該是 setScaleY(float xxx)的樣式;這時,系統(tǒng)就會利用反射來找到 setScaleY(float xxx)函數(shù),并把當(dāng)前的動畫數(shù)值做為參數(shù)傳進去。 那問題來了,如果沒有類似 setScaleY(float xxx)的函數(shù),我們只實現(xiàn)了一個 setScaleY(int xxx)的函數(shù)怎么辦?這里雖然函數(shù)名一樣,但參數(shù)類型是不一樣的,那么系統(tǒng)就會報一個錯誤:

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

意思就是對應(yīng)函數(shù)的指定參數(shù)類型沒有找到。 (3)、調(diào)用 set 函數(shù)以后怎么辦?從 ObjectAnimator 的流程可以看到,ObjectAnimator 只負責(zé)把動畫過程中的數(shù)值傳到對應(yīng)屬性的 set 函數(shù)中就結(jié)束了,注意傳給 set 函數(shù)以后就結(jié)束了!set 函數(shù)就相當(dāng)我們在 ValueAnimator 中添加的監(jiān)聽的作用,set 函數(shù)中的對控件的操作還是需要我們自己來寫的。

那我們來看看 View 中的 setScaleY 是怎么實現(xiàn)的吧:

/** 
 * Sets the amount that the view is scaled in Y around the pivot point, as a proportion of 
 * the view's unscaled width. A value of 1 means that no scaling is applied. 
 * 
 * @param scaleY The scaling factor. 
 * @see #getPivotX() 
 * @see #getPivotY() 
 * 
 * @attr ref android.R.styleable#View_scaleY 
 */  
public void setScaleY(float scaleY) {  
    ensureTransformationInfo();  
    final TransformationInfo info = mTransformationInfo;  
    if (info.mScaleY != scaleY) {  
        invalidateParentCaches();  
        // Double-invalidation is necessary to capture view's old and new areas  
        invalidate(false);  
        info.mScaleY = scaleY;  
        info.mMatrixDirty = true;  
        mPrivateFlags |= DRAWN; // force another invalidation with the new orientation  
        invalidate(false);  
    }  
} 

大家不必理解這一坨代碼的意義,因為這些代碼是需要讀懂 View 的整體流程以后才能看得懂的,只需要跟著我的步驟來理解就行。這段代碼總共分為兩部分:第一步重新設(shè)置當(dāng)前控件的參數(shù),第二步調(diào)用 Invalidate()強制重繪; 所以在重繪時,控件就會根據(jù)最新的控件參數(shù)來繪制了,所以我們就看到當(dāng)前控件被縮放了。 (4)、set 函數(shù)調(diào)用頻率是多少:由于我們知道動畫在進行時,每隔十幾毫秒會刷新一次,所以我們的 set 函數(shù)也會每隔十幾毫秒會被調(diào)用一次。 講了這么多,就是為了強調(diào)一點:ObjectAnimator 只負責(zé)把當(dāng)前運動動畫的數(shù)值傳給 set 函數(shù)。至于 set 函數(shù)里面怎么來做,是我們自己的事了。 好了,在知道了 ObjectAnimator 的原理以后,下面就來看看如何自定義一個 ObjectAnimator 的屬性吧。

二、自定義 ObjectAnimator 屬性

上面我們已經(jīng)看了使用 View 自帶的 set 函數(shù)所對應(yīng)屬性的方法,而且理解了 ObjectAnimator 的動畫實現(xiàn)原理,下面我們來自定義一個屬性來看看實現(xiàn)效果吧。 我們在開始之前再來捋一下 ObjectAnimator 的動畫設(shè)置流程:ObjectAnimator 需要指定操作的控件對象,在開始動畫時,到控件類中去尋找設(shè)置屬性所對應(yīng)的 set 函數(shù),然后把動畫中間值做為參數(shù)傳給這個 set 函數(shù)并執(zhí)行它。 所以,我們說了,控件類中必須所要設(shè)置屬性所要對應(yīng)的 set 函數(shù)。所以為了自由控制控件的實現(xiàn),我們這里自定義一個控件。大家知道在這個自定義控件中,肯定存在一個 set 函數(shù)與我們自定義的屬性相對應(yīng)。 我們先來看看這段要實現(xiàn)的效果:

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

這個效果圖與我們上篇自定義控件實現(xiàn)的效果差不多,這個控件中存在一個圓形,也是在動畫時先將這個圓形放大,然后再將圓形還原。

1、保存圓形信息類——Point

為了,保存圓形的信息,我們先定義一個類:(Point.java)

public class Point {  
    private int mRadius;  

    public Point(int radius){  
        mRadius = radius;  
    }  

    public int getRadius() {  
        return mRadius;  
    }  

    public void setRadius(int radius) {  
        mRadius = radius;  
    }  
}  

這個類很好理解,只有一個成員變量 mRadius,表示圓的半徑。

2、自定義控件——MyPointView

然后我們自定義一個控件 MyPointView,完整代碼如下:

public class MyPointView extends View {  
    private Point mPoint = new Point(100);  

    public MyPointView(Context context, AttributeSet attrs) {  
        super(context, attrs);  
    }  

    @Override  
    protected void onDraw(Canvas canvas) {  
        if (mPoint != null){  
            Paint paint = new Paint();  
            paint.setAntiAlias(true);  
            paint.setColor(Color.RED);  
            paint.setStyle(Paint.Style.FILL);  
            canvas.drawCircle(300,300,mPoint.getRadius(),paint);  
        }  
        super.onDraw(canvas);  
    }  

    void setPointRadius(int radius){  
        mPoint.setRadius(radius);  
        invalidate();  
    }  

}  

在這段代碼中,首先來看我們前面講到的 set 函數(shù):

void setPointRadius(int radius){  
    mPoint.setRadius(radius);  
    invalidate();  
}  

第一點,這個 set 函數(shù)所對應(yīng)的屬性應(yīng)該是 pointRadius 或者 PointRadius。前面我們已經(jīng)講了第一個字母大小寫無所謂,后面的字母必須保持與 set 函數(shù)完全一致。 第二點,在 setPointRadius 中,先將當(dāng)前動畫傳過來的值保存到 mPoint 中,做為當(dāng)前圓形的半徑。然后強制界面刷新 在界面刷新后,就開始執(zhí)行 onDraw()函數(shù):

@Override  
protected void onDraw(Canvas canvas) {  
    if (mPoint != null){  
        Paint paint = new Paint();  
        paint.setAntiAlias(true);  
        paint.setColor(Color.RED);  
        paint.setStyle(Paint.Style.FILL);  
        canvas.drawCircle(300,300,mPoint.getRadius(),paint);  
    }  
    super.onDraw(canvas);  
}  

在 onDraw 函數(shù)中,就是根據(jù)當(dāng)前 mPoint 的半徑值在(300,300)點外畫一個圓;有關(guān)畫圓的知識,大家可以參考《android Graphics(一):概述及基本幾何圖形繪制》

3、使用 MyPointView

首先,在 MyActivity 的布局中添加 MyPointView 的使用(main.xml):

<?xml version="1.0" encoding="utf-8"?>  
<RelativeLayout 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:layout_alignParentLeft="true"  
            android:padding="10dp"  
            android:text="start anim"  
            />  

    <Button  
            android:id="@+id/btn_cancel"  
            android:layout_width="wrap_content"  
            android:layout_height="wrap_content"  
            android:layout_alignParentRight="true"  
            android:padding="10dp"  
            android:text="cancel anim"  
            />  
    <TextView  
            android:id="@+id/tv"  
            android:layout_width="100dp"  
            android:layout_height="wrap_content"  
            android:layout_centerHorizontal="true"  
            android:gravity="center"  
            android:padding="10dp"  
            android:background="#ffff00"  
            android:text="Hello qijian"/>  

    <com.example.BlogObjectAnimator1.MyPointView  
            android:id="@+id/pointview"  
            android:layout_width="match_parent"  
            android:layout_height="match_parent"  
            android:layout_below="@id/tv"/>  

</RelativeLayout> 

布局代碼很好理解,根據(jù)效果圖中的布局效果來理解,非常容易,就不再多講 然后看看在 MyActivity 中,點擊 start anim 后的處理方法:

public class MyActivity extends Activity {  
    private Button btnStart;  
    private MyPointView mPointView;  

    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  

        btnStart = (Button) findViewById(R.id.btn);  
        mPointView = (MyPointView)findViewById(R.id.pointview);  

        btnStart.setOnClickListener(new View.OnClickListener() {  
            @Override  
            public void onClick(View v) {  
                doPointViewAnimation();  
            }  
        });  
    }  
  …………  
} 

在點擊 start anim 按鈕后,開始執(zhí)行 doPointViewAnimation()函數(shù),doPointViewAnimation()函數(shù)代碼如下:

private void doPointViewAnimation(){  
     ObjectAnimator animator = ObjectAnimator.ofInt(mPointView, "pointRadius", 0, 300, 100);  
      animator.setDuration(2000);  
      animator.start();  
}  

在這段代碼中,著重看 ObjectAnimator 的構(gòu)造方法,首先要操作的控件對象是 mPointView,然后對應(yīng)的屬性是 pointRadius,然后值是從 0 到 300 再到 100; 所以在動畫開始以后,ObjectAnimator 就會實時地把動畫中產(chǎn)生的值做為參數(shù)傳給 MyPointView 類中的 setPointRadius(int radius)函數(shù),然后調(diào)用 setPointRadius(int radius)。由于我們在 setPointRadius(int radius)中實時地設(shè)置圓形的半徑值然后強制重繪當(dāng)前界面,所以可以看到圓形的半徑會隨著動畫的進行而改變。 源碼在文章底部給出

四、注意——何時需要實現(xiàn)對應(yīng)屬性的 get 函數(shù)

我們再來看一下 ObjectAinimator 的下面三個構(gòu)造方法:

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) 

前面我們已經(jīng)分別講過三個函數(shù)的使用方法,在上面的三個構(gòu)造方法中最后一個參數(shù)都是可變長參數(shù)。我們也講了,他們的意義就是從哪個值變到哪個值的。 那么問題來了:前面我們都是定義多個值,即至少兩個值之間的變化,那如果我們只定義一個值呢,如下面的方式:(同樣以 MyPointView 為例)

ObjectAnimator animator = ObjectAnimator.ofInt(mPointView, "pointRadius",100);

我們在這里只傳遞了一個變化值 100;那它從哪里開始變化呢?我們來看一下效果: 代碼如下:

ObjectAnimator animator = ObjectAnimator.ofInt(mPointView, "pointRadius",100);  
animator.setDuration(2000);  
animator.start();  

效果圖如下:

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

從效果圖中看起來是從 0 開始的,但是看 log 可以看出來已經(jīng)在出警告了:

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

我們點了三次 start anim 按鈕,所以這里也報了三次,意思就是沒找到 pointRadius 屬性所對應(yīng)的 getPointRadius()函數(shù); 僅且僅當(dāng)我們只給動畫設(shè)置一個值時,程序才會調(diào)用屬性對應(yīng)的 get 函數(shù)來得到動畫初始值。如果動畫沒有初始值,那么就會使用系統(tǒng)默認值。比如 ofInt()中使用的參數(shù)類型是 int 類型的,而系統(tǒng)的 Int 值的默認值是 0,所以動畫就會從 0 運動到 100;也就是系統(tǒng)雖然在找到不到屬性對應(yīng)的 get 函數(shù)時,會給出警告,但同時會用系統(tǒng)默認值做為動畫初始值。 如果通過給自定義控件 MyPointView 設(shè)置了 get 函數(shù),那么將會以 get 函數(shù)的返回值做為初始值:

public class MyPointView extends View {  
    private Point mPoint = new Point(100);  

    public MyPointView(Context context, AttributeSet attrs) {  
        super(context, attrs);  
    }  

    @Override  
    protected void onDraw(Canvas canvas) {  
        if (mPoint != null){  
            Paint paint = new Paint();  
            paint.setAntiAlias(true);  
            paint.setColor(Color.RED);  
            paint.setStyle(Paint.Style.FILL);  
            canvas.drawCircle(300,300,mPoint.getRadius(),paint);  
        }  
        super.onDraw(canvas);  
    }  

    public int getPointRadius(){  
        return 50;  
    }  

    public void setPointRadius(int radius){  
        mPoint.setRadius(radius);  
        invalidate();  
    }  

} 

我們在這里添加了 getPointRadius 函數(shù),返回值是 Int.有些同學(xué)可能會疑惑:我怎么知道這里要返回 int 值呢? 我們前面說過當(dāng)且僅當(dāng)我們在創(chuàng)建 ObjectAnimator 時,只給他傳遞了一個過渡值的時候,系統(tǒng)才會調(diào)用屬性對應(yīng)的 get 函數(shù)來得到動畫的初始值!所以做為動畫的初始值,那么在創(chuàng)建動畫時過渡值傳的什么類型,這里的 get 函數(shù)就要返回類型

public static ObjectAnimator ofObject(Object target, String propertyName,TypeEvaluator evaluator, Object... values)

比如上面的 ofObject,get 函數(shù)所返回的類型就是與最后一個參數(shù) Object... values,相同類型的。 在我們在 MyPointView 添加上 PointRadius 所對應(yīng)的 get 函數(shù)以后重新執(zhí)行動畫:

ObjectAnimator animator = ObjectAnimator.ofInt(mPointView, "pointRadius",100);  
animator.setDuration(2000);  
animator.start();  

此時的效果圖如下:

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

從動畫中可以看出,半徑已經(jīng)不是從 0 開始的了,而是從 50 開始的。 最后我們總結(jié)一下:當(dāng)且僅當(dāng)動畫的只有一個過渡值時,系統(tǒng)才會調(diào)用對應(yīng)屬性的 get 函數(shù)來得到動畫的初始值。

源碼在文章底部給出

三、常用函數(shù)

有關(guān)常用函數(shù)這一節(jié)其實沒有太多講的必要。因為 ObjectAnimator 的函數(shù)都是從 ValueAnimator 中繼承而來的,所以用法和效果與 ValueAnimator 是完全一樣的。我們這里只講解一下 Evaluator 的用法,其它的也就不再講了。

1、使用 ArgbEvaluator

我們搜一下 TextView 所有的函數(shù)發(fā)現(xiàn),TextView 有一個 set 函數(shù)能夠改變背景色:

public void setBackgroundColor(int color);  

大家可以回想到,我們在 ValueAnimator 中也曾改變過背景色,使用的是 ArgbEvaluator。在這里我們再回顧下 ArgbEvaluator,它的實現(xiàn)代碼如下:

public class ArgbEvaluator implements TypeEvaluator {  
    public Object evaluate(float fraction, Object startValue, Object endValue) {  
        int startInt = (Integer) startValue;  
        int startA = (startInt >> 24);  
        int startR = (startInt >> 16) & 0xff;  
        int startG = (startInt >> 8) & 0xff;  
        int startB = startInt & 0xff;  

        int endInt = (Integer) endValue;  
        int endA = (endInt >> 24);  
        int endR = (endInt >> 16) & 0xff;  
        int endG = (endInt >> 8) & 0xff;  
        int endB = endInt & 0xff;  

        return (int)((startA + (int)(fraction * (endA - startA))) << 24) |  
                (int)((startR + (int)(fraction * (endR - startR))) << 16) |  
                (int)((startG + (int)(fraction * (endG - startG))) << 8) |  
                (int)((startB + (int)(fraction * (endB - startB))));  
    }  
}  

有關(guān)它具體實現(xiàn)的原理,前面篇章中我們已經(jīng)講過了,這里主要說一點,ArgbEvaluator 的返回值是 Integer 類型,所以我們要使用 ArgbEvaluator 的話,構(gòu)造 ObjectAnimator 時必須使用 ofInt() 下面我們來看看使用 ArgbEvaluator 的代碼:

ObjectAnimator animator = ObjectAnimator.ofInt(tv, "BackgroundColor", 0xffff00ff, 0xffffff00, 0xffff00ff);  
animator.setDuration(8000);  
animator.setEvaluator(new ArgbEvaluator());  
animator.start();

然后我們來看下代碼效果:

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

源碼在文章底部給出

2、其它函數(shù)

下面把其它所涉及到的函數(shù)的列表列在下面,大家可以參考 ValueAnimator 的使用方法來使用。有關(guān)自定義插值器和 Evaluator 的部分,可以參考《Animation 動畫詳解(五)——高級進階(一)》 (1)、常用函數(shù)

/** 
 * 設(shè)置動畫時長,單位是毫秒 
 */  
ValueAnimator setDuration(long duration)  
/** 
 * 獲取 ValueAnimator 在運動時,當(dāng)前運動點的值 
 */  
Object getAnimatedValue();  
/** 
 * 開始動畫 
 */  
void start()  
/** 
 * 設(shè)置循環(huán)次數(shù),設(shè)置為 INFINITE 表示無限循環(huán) 
 */  
void setRepeatCount(int value)  
/** 
 * 設(shè)置循環(huán)模式 
 * value 取值有 RESTART,REVERSE, 
 */  
void setRepeatMode(int value)  
/** 
 * 取消動畫 
 */  
void cancel()  
(2)、監(jiān)聽器相關(guān)
[java] view plain
/** 
 * 監(jiān)聽器一:監(jiān)聽動畫變化時的實時值 
 */  
public static interface AnimatorUpdateListener {  
    void onAnimationUpdate(ValueAnimator animation);  
}  
//添加方法為:public void addUpdateListener(AnimatorUpdateListener listener)  
/** 
 * 監(jiān)聽器二:監(jiān)聽動畫變化時四個狀態(tài) 
 */  
public static interface AnimatorListener {  
    void onAnimationStart(Animator animation);  
    void onAnimationEnd(Animator animation);  
    void onAnimationCancel(Animator animation);  
    void onAnimationRepeat(Animator animation);  
}  
//添加方法為:public void addListener(AnimatorListener listener)

(3)、插值器與 Evaluator

/** 
 * 設(shè)置插值器 
 */  
public void setInterpolator(TimeInterpolator value)  
/** 
 * 設(shè)置 Evaluator 
 */  
public void setEvaluator(TypeEvaluator value) 

到這里,有關(guān) ObjectAnimator 的知識就講完了,下篇再講講聯(lián)合動畫和 xml 中實現(xiàn)動畫的方法。

如果本文有幫到你,記得加關(guān)注哦 源碼下載地址:

csdn:http://download.csdn.net/detail/harvic880925/9445785

github:https://github.com/harvic/BlogResForGitHub

請大家尊重原創(chuàng)者版權(quán),轉(zhuǎn)載請標明出處,謝謝