上幾篇給大家講了 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)
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ù)的值是啥呢?
我們再回來看構(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 的效果:
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
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
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)控件動畫效果的。
我們先來看張圖:
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 的屬性吧。
上面我們已經(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)的效果差不多,這個控件中存在一個圓形,也是在動畫時先將這個圓形放大,然后再將圓形還原。
為了,保存圓形的信息,我們先定義一個類:(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,表示圓的半徑。
然后我們自定義一個控件 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(一):概述及基本幾何圖形繪制》
首先,在 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)前界面,所以可以看到圓形的半徑會隨著動畫的進行而改變。 源碼在文章底部給出
我們再來看一下 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ù)來得到動畫的初始值。
源碼在文章底部給出
有關(guān)常用函數(shù)這一節(jié)其實沒有太多講的必要。因為 ObjectAnimator 的函數(shù)都是從 ValueAnimator 中繼承而來的,所以用法和效果與 ValueAnimator 是完全一樣的。我們這里只講解一下 Evaluator 的用法,其它的也就不再講了。
我們搜一下 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="" />
源碼在文章底部給出
下面把其它所涉及到的函數(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)載請標明出處,謝謝