前言
之前我們把視圖動畫(也就是View動畫)分析的差不多了,當然幀動畫我們沒有講解,其實幀動畫比較簡單,就是通過順序播放一系列的圖像從而產生動畫效果,可以簡單理解為圖片的切換。和我們小時候玩的翻書讓物體動起來是一個道理。它使用起來也比較簡單。所以我們就不單獨拿出來講解。到后面我們會用到時再去簡單講解。這篇我們繼續來學習動畫之屬性動畫(Property Animator)。
介紹
我們在第一篇文章的時候就提到過動畫的分類:視圖動畫,屬性動畫。當時我們講解了2者的區別。但是我們沒有分析具體2者的不同與使用場景。并且已經有了View動畫,為何有加入屬性動畫呢?
-
Property Animator能實現補間動畫無法實現的功能 ;
- 比如我們想將一個控件的寬度增加,用動畫來這么做呢?有人會覺得直接用縮放(scaleX)來做,但是做出來的效果卻是將控件寬度拉長而不是增加。不管是從視覺上還是理解上都不是我們想要的效果。后期我們會做實驗來試一下。再者我們想改變一個控件顏色用View動畫也是無法做到的,因為View動畫只能對派生自View的控件實例起作用;。但是屬性動畫卻可以對任意"對象"起作用,甚至是沒有對象。它可以達到的效果為:在一個時間間隔內,完成對象從一個屬性值到里一個屬性值的改變,所以,屬性動畫幾乎無所不能。名字中可以看出屬性動畫,應該是作用于控件屬性的!正因為屬性動畫能夠只針對控件的某一個屬性來做動畫,所以也就造就了他能單獨改變控件的某一個屬性的值!比如顏色!這就是Property Animator能實現補間動畫無法實現的功能的最重要原因。
-
View Animation僅能對指定的控件做動畫,而Property Animator是通過改變控件某一屬性值來做動畫的。
- View動畫之所以叫視圖動畫,因為它做動畫是對控件的視圖,影像做動畫,并沒有改變控件的屬性。所以當我們用視圖做動畫完成后造成點擊事件與setVisibility(View.GONE)失效。那么我們就可以得出結論:補間動畫雖能對控件做動畫,但并沒有改變控件內部的屬性值。而Property Animator則是恰恰相反,Property Animator是通過改變控件內部的屬性值來達到動畫效果的。
那事實到底是不是這樣的呢?下面我們就用實際的例子來證實一下。那我實際運行下:
可以看到,當我們沒有做動畫的時候隱藏控件與點擊事件都是有效的。但是當我們在動畫完成后,點擊控件卻沒有響應點擊事件,同時隱藏也無效。但是點擊控件初始位置卻可以響應點擊事件。這就說明View動畫雖能對控件做動畫,但并沒有改變控件內部的屬性值。
提示: 如果想隱藏的話可以使用view.clearAnimation()清楚View動畫。
ValueAnimator
ValueAnimator本身不作用與任何對象,也就是說直接使用時沒有任何動畫效果的。它可以對一個值做動畫。然后我們可以監聽其動畫的過程,在動畫的過程中修改我們對象的屬性值,這樣也就相當于對我們的對象做了動畫。下面我們就來使用下。
-
常用方法
在使用之前,我們先來看下ValueAnimator常用的方法有哪些:
創建對象
一般情況我們會調用ValueAnimator的靜態方法創建對象。
參數類型都是可變參數長參數,所以我們可以傳入任何數量的值;傳進去的值列表,就表示動畫時的變化范圍;比如ofInt(2,90,45)就表示從數值2變化到數字90再變化到數字45;所以我們傳進去的數字越多,動畫變化就越復雜。從參數類型也可以看出ofInt與ofFloat的唯一區別就是傳入的數字類型不一樣,ofInt需要傳入Int類型的參數,而ofFloat則表示需要傳入Float類型的參數。
public static ValueAnimator ofInt(int... values)
public static ValueAnimator ofFloat(float... values)
常用方法
·
/**
* 延時多久時間開始,單位是毫秒
*/
public void setStartDelay(long startDelay)
/**
* 設置動畫時長,單位是毫秒
*/
ValueAnimator setDuration(long duration)
/**
* 獲取ValueAnimator在運動時,當前運動點的值
*/
Object getAnimatedValue();
/**
* 開始動畫
*/
void start()
/**
* 設置循環次數,設置為INFINITE表示無限循環
*/
void setRepeatCount(int value)
/**
* 設置循環模式
* value取值有RESTART,REVERSE,
*/
void setRepeatMode(int value)
/**
* 取消動畫
*/
void cancel()
/**
* 暫畫動畫
*/
void pause()
/**
* 繼續動畫
*/
void resume()
這里面方法都比較簡單,這里我們介紹下
Object getAnimatedValue();
這個方法的含義是:獲取ValueAnimator在運動時,當前運動點的值,返回Object。如何理解呢?我們知道在創建對象的時候我們有兩個方法一個是傳入int一個float,這里就是獲取相應某一時間當前運動點的值。傳入的是int返回就是int,返回float就是float。為了更方便理解下面我們實際使用下,使用方法如下:
- 創建ValueAnimator對象
ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 400);
valueAnimator.setDuration(2000);
- 添加監聽
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int curValue = (int) animation.getAnimatedValue();
Log.d("qijian", "curValue:" + curValue);
mTextView.layout(curValue, curValue, curValue + mTextView.getWidth(), curValue + mTextView.getHeight());
}
});
- 開啟動畫
valueAnimator.start();
這里我們利用ofInt創建對象,傳入(0,400)這里的含義是利用ValueAnimator動畫創建一個從0-400一個改變的值,然后設置其數值變換的監聽,在監聽內部獲取到從動畫開始到結束時間內變換的數值,然后將在變化中重新設置textview的位置,使textview從屏幕(0,0)點運動到(400,400)點。
<font color=#006400>valueAnimator.addUpdateListener()</font> 監聽數值變換的監聽。這里意思就是動畫時長為2s,在2s內數值變換0-400,每次變換都會調用這個監聽在這個監聽里面我們可以獲取到具體變換的數值。
<font color=#006400>int curValue = (int) animation.getAnimatedValue();</font> 這個方法就是上面我們講到的,獲取當前動畫運動點的值
<font color=#006400>mTextView.layout()</font>這個方法是設置textView的布局。里面參數分別對應控件所在矩形的左上右下四個點。我們這里動態設置變換的數值從而達到動畫的效果。
下面我們來看下效果:
監聽:
12-24 02:26:21.690 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:0
12-24 02:26:21.709 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:0
12-24 02:26:21.729 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:0
12-24 02:26:21.749 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:1
12-24 02:26:21.771 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:1
12-24 02:26:21.797 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:3
12-24 02:26:21.821 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:4
12-24 02:26:21.845 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:6
12-24 02:26:21.863 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:8
12-24 02:26:21.889 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:11
省略中間部分.....
12-24 02:26:23.543 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:395
12-24 02:26:23.560 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:396
12-24 02:26:23.581 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:397
12-24 02:26:23.597 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:398
12-24 02:26:23.616 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:398
12-24 02:26:23.623 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:399
12-24 02:26:23.642 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:399
12-24 02:26:23.656 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:399
12-24 02:26:23.674 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:400
可以看到在監聽中獲取到的值確實是從0到400變換。也實現了我們動畫的效果。
監聽
ValueAnimator中共有兩個監聽器:
- 添加監聽器
/**
* 監聽器一:監聽動畫變化時的實時值
*/
public static interface AnimatorUpdateListener {
void onAnimationUpdate(ValueAnimator animation);
}
//添加方法為:public void addUpdateListener(AnimatorUpdateListener listener)
/**
* 監聽器二:監聽動畫變化時四個狀態
*/
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)
/**
* 監聽器三:監聽動畫暫停與重新開始
*/
public static interface AnimatorPauseListener {
void onAnimationPause(Animator animation);
void onAnimationResume(Animator animation);
}
//添加方法為:public void addPasueListener(AnimatorPauseListener listener)
監聽器一:AnimatorUpdateListener就是監聽動畫的實時變化狀態,在onAnimationUpdate(ValueAnimator animation)中的animation表示當前狀態動畫的實例。
監聽器二:主要是監聽Animation的四個狀態,start、end、cancel、repeat;當動畫開始時,會調用onAnimationStart(Animator animation)方法,當動畫結束時調用onAnimationEnd(Animator animation),當動畫取消時,調用onAnimationCancel(Animator animation)函數,當動畫重復時,會調用onAnimationRepeat(Animator animation)函數。
監聽器三:監聽動畫暫停與重新開始
- 取消監聽器
/**
* 移除AnimatorUpdateListener
*/
void removeUpdateListener(AnimatorUpdateListener listener);
void removeAllUpdateListeners();
/**
* 移除AnimatorListener
*/
void removeListener(AnimatorListener listener);
void removeAllListeners();
/**
* 移除AnimatorPauseListener
*/
valueAnimator.removePauseListener(AnimatorPauseListener listener);
針對AnimatorUpdateListener和AnimatorListener,每個監聽器都有兩個方法來移除;我們就以移除AnimatorListener來簡單講一下,removeListener(AnimatorListener listener)用于在animator中移除指定的監聽器,而removeAllListeners()用于移除animator中所有的AnimatorListener監聽器;
下面我們測試一下,效果:
這里方法對應關系start()->cancel() pause() ->resume()
從打印中我們可以看到開始和繼續的區別 結束和暫停的區別。當我移除 AnimatorListener時狀態就不在打印但是動畫在運動,移除AnimatorUpdateListener動畫會停止。因為我們在AnimatorUpdateListener監聽中獲取到的值,所以移除監聽后我們就獲取不到改變的值了,所以動畫也就停止了。
- 更多函數:
/**
* 完全克隆一個ValueAnimator實例,包括它所有的設置以及所有對監聽器代碼的處理
*/
public ValueAnimator clone()
克隆就是完全一樣!注意是完全一樣!就是復制出來一個完全一樣的新的ValueAnimator實例出來。對原來的那個ValueAnimator是怎么處理的,在這個新的實例中也是全部一樣的。
注意: 克隆得到的新對象newAnimator與之前對象是2個不同的對象。對newAnimator進行的所有操作不會影響到valueAnimator對象。
使用:
ValueAnimator newAnimator = valueAnimator.clone();
其他更多函數請查閱文檔
結語
到這里ValueAnimator的基本使用與View動畫的區別就差不多了。
感謝
站在巨人的肩膀上可以讓我們看的更遠。
Android自定義控件三部曲文章