Android動畫詳解之Android 動畫屬性和實現方法之屬性動畫(三)

屬性動畫
(一)、屬性動畫概念:
        屬性動畫,這個是在Android 3.0中才引進的。Property Animation故名思議就是通過動畫的方式改變對象的屬性.屬性動畫更改的是對象的實際屬性,在View Animation(Tween Animation)中,其改變的是View的繪製效果,真正的View的屬性保持不變。可以將屬性動畫理解爲增強版的補間動畫。
        比如無論如何縮放Button的大小,Button的有效點擊區域還是沒有應用動畫時的區域,其位置與大小都不變。而在Property Animation中,改變的是對象的實際屬性,如Button的縮放,Button的位置與大小屬性值都改變了。
        Property Animation不止可以應用於View,還可以應用於任何對象。Property Animation只是表示一個值在一段時間內的改變,當值改變時要做什麼事情完全是你自己決定的。


(二)爲什麼引入屬性動畫
Android3.0之前提供的補間動畫機制還算相對比較健全的,比如你的需求中只需要對View進行移動、縮放、旋轉和淡入淡出的操作,那麼補間動畫已經足夠健全了。但是,如果一旦需求超出了這四種操作,補間動畫就無能爲力了。 
例如,我們需要改變View的寬度,這個時候就不能通過補間動畫實現。此外,補間動畫還有一個最大的缺陷,就是它只是改變了View的顯示效果而已,並不會真正的改變View的屬性。具體來說,例如屏幕左上角有一個Button,使用補間動畫將其移動到右下角,此刻你去點擊右下角的Button,它是絕對不會響應點擊事件的,因此其作用區域依然還在左上角。只不過是補間動畫將其繪製在右下角而已。
(三)、屬性動畫常用屬性:
Duration動畫的持續時間,默認300ms。android:duration屬性(對應的xml文件)
Time interpolation:時間插值。LinearInterpolator、AccelerateDecelerateInterpolator,定義動畫的變化率。android:interpolator屬性
Repeat count and behavior:重複次數、以及重複模式;可以定義重複多少次;重複時從頭開始(restart),還是反向(reverse)。android:repeatCount屬性(可以是整數也可以是infinite(無限))android:repeatMode="restart"  
Animator sets: 動畫集合,你可以定義一組動畫,一起執行或者順序執行。<set/>,該元素的android:ordering屬性指定該組動畫是按次序播放還是同時播放。有兩個值(sequentially和together分別表示先後執行和同步執行)
Frame refresh delay:幀刷新延遲(幀刷新頻率,每個多久播放一幀);默認爲10ms,但最終依賴系統的當前狀態。
(三)、屬性動畫API:相關的類
ObjectAnimator 動畫的執行類(是ValueAnimator的子類,使用簡單常用。少數場景下,由於其存在一些限制,再考慮使用ValueAnimator)
ValueAnimator 動畫的執行類
AnimatorSet 用於控制一組動畫的執行:線性,一起,每個動畫的先後執行等。
AnimatorInflater 用戶加載屬性動畫的xml文件
TypeEvaluator 類型估值,主要用於設置動畫操作屬性的值。
TimeInterpolator 時間插值
總的來說,屬性動畫就是,動畫的執行類來設置動畫操作的對象的屬性、持續時間,開始和結束的屬性值,時間差值等,然後系統會根據設置的參數動態的變化對象的屬性。


ValueAnimator
ValueAnimator是整個屬性動畫機制當中最核心的一個類,前面我們已經提到了,屬性動畫的運行機制是通過不斷地對值進行操作來實現的,而初始值和結束值之間的動畫過渡就是由ValueAnimator這個類來負責計算的。它的內部使用一種時間循環的機制來計算值與值之間的動畫過渡,我們只需要將初始值和結束值提供給ValueAnimator,並且告訴它動畫所需運行的時長,那麼ValueAnimator就會自動幫我們完成從初始值平滑地過渡到結束值這樣的效果。除此之外,ValueAnimator還負責管理動畫的播放次數、播放模式、以及對動畫設置監聽器等,確實是一個非常重要的類。




  ValueAnimator 常用方法:
  1、ofFloat()小數位的動畫過渡
 2、ofInt()整數位的動畫過度
 3、ofObject()
 4、setStartDelay()動畫播放延遲時間
 5、setRepeatCount()動畫循環次數
 6、setRepeatMode()循環模式:RESTART和REVERSE是重新播放和倒敘播放


valuseAnimator的使用比較簡單,可以是一個單一的過渡,沒有界面效果:

private void ValueTest(View view){
    //將值從0過度到1
    ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
    //可以設置多個這樣就是從0到1再到0.5
    //ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f,0.5f);
    anim.setDuration(300);
    anim.start();
}
但是這樣無法知道他是否是執行了,可以通過添加一個動畫的監聽器來監聽他的回調,利用addUpdateListener()方法:
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        float currentValue = (float) animation.getAnimatedValue();
        Log.e("ceshi", "cuurent value is " + currentValue);
    }
});
將結果打印出來可以看到

ValueAnimator確實已經在正常工作了,值在300毫秒的時間內從0平滑過渡到了1。
也可以調用setStartDelay()設置動畫延時播放的時間,和setRepeatCount()循環次數和setRepeatMode()循環模式

ObjectAnimator
相比於ValueAnimator,ObjectAnimator可能纔是我們最常接觸到的類,因爲ValueAnimator只不過是對值進行了一個平滑的動畫過渡,但我們實際使用到這種功能的場景好像並不多。而ObjectAnimator則就不同了,它是可以直接對任意對象的任意屬性進行動畫操作的,比如說View的alpha屬性。
不過雖說ObjectAnimator會更加常用一些,但是它其實是繼承自ValueAnimator的,底層的動畫實現機制也是基於ValueAnimator來完成的,因此ValueAnimator仍然是整個屬性動畫當中最核心的一個類。那麼既然是繼承關係,說明ValueAnimator中可以使用的方法在ObjectAnimator中也是可以正常使用的,它們的用法也非常類似。
如果想將圖片在3000毫秒內變成半透明再還原,可以這麼寫:

//它是可以直接對任意對象的任意屬性進行動畫操作的
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "alpha", 1f, 0f, 1f);
animator.setDuration(2000);
//設置循環次數
animator.setRepeatCount(2);
//設置循環方式
animator.setRepeatMode(ValueAnimator.RESTART);
animator.start();
這裏ofFloat()內的參數中第一個需要傳入一個object對象,就是需要動畫實現的對象;
第二個參數是想對對象的那個屬性進行動畫操作;
第三個和以後的參數與ValueAnimator一致;
實現效果如下:


還可以按照一樣的思路實現旋轉縮放和移動
旋轉代碼:

//設置旋轉
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "rotation", 0f,360f);
animator.setDuration(2000);
animator.start();
縮放代碼:
//設置縮放
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "scaleX", 1.0f,0.5f,1.0f);
animator.setDuration(2000);
animator.start();
移動代碼:
//設置移動
//獲取圖片當前位置
float initialX = myImageView.getTranslationX();
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "translationX", initialX,-200,initialX);
animator.setDuration(5000);
//設置動畫插入器
animator.setInterpolator(new AccelerateInterpolator());
animator.start();
效果如下:


設置了動畫插入器橫向移動的時候先慢後快。
比較重要的是:
//ObjectAnimator.ofFloat第二個參數可以放置任意的值,其中(alpha、rotation、translationX、translationY和scaleY、scaleX這幾個值,分別可以完成淡入淡出、旋轉、水平或垂直移動、垂直或水平縮放縮放這幾種動畫)

組合動畫
獨立的動畫能夠實現的視覺效果畢竟是相當有限的,因此將多個動畫組合到一起播放就顯得尤爲重要。幸運的是,Android團隊在設計屬性動畫的時候也充分考慮到了組合動畫的功能,因此提供了一套非常豐富的API來讓我們將多個動畫組合到一起。
實現組合動畫功能主要需要藉助AnimatorSet這個類,這個類提供了一個play()方法,如果我們向這個方法中傳入一個Animator對象(ValueAnimator或ObjectAnimator)將會返回一個AnimatorSet.Builder的實例,AnimatorSet.Builder中包括以下四個方法:
after(Animator anim)   將現有動畫插入到傳入的動畫之後執行
after(long delay)   將現有動畫延遲指定毫秒後執行
before(Animator anim)   將現有動畫插入到傳入的動畫之前執行
with(Animator anim)   將現有動畫和傳入的動畫同時執行
先整體縮放再淡入淡出,效果如下:

代碼實現:
1、利用AnimatorSet實現組合動畫,這個是最豐富的可以實現動畫前後順序的處理
//利用AnimatorSet實現組合動畫,這個是最豐富的可以實現動畫前後順序的處理
ObjectAnimator scaleXAnim = ObjectAnimator.ofFloat(view, "scaleX", 1f, 0.5f);
ObjectAnimator scaleYAnim = ObjectAnimator.ofFloat(view, "scaleY", 1f, 0.5f);
ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(view, "alpha", 1f, 0.5f);
AnimatorSet animSet = new AnimatorSet();
animSet.play(scaleXAnim).with(scaleYAnim).before(alphaAnim);
animSet.setDuration(3000);
animSet.start();
2、利用動畫刷新監聽實現組合動畫,第二個參數隨便寫,只能一起執行
//利用動畫刷新監聽實現組合動畫,第二個參數隨便寫,只能一起執行
ObjectAnimator anim = ObjectAnimator.ofFloat(view,"lw",1.0f,0.0f,1f);
anim.setDuration(5000);
anim.start();
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        float cVal = (Float) animation.getAnimatedValue();
        view.setAlpha(cVal);
        view.setScaleX(cVal);
        view.setScaleY(cVal);
    }
});
3、除了上面Animator類還可以使用PropertyValuesHolder類來實現組合動畫,
 不過這個組合動畫就沒有上面的豐富了,使用PropertyValuesHolder類只能多個動畫一起執行。
 當然我們得結合 ObjectAnimator.ofPropertyValuesHolder(Object target,PropertyValuesHolder… values);
 方法來使用。第一個參數是動畫的目標對象,之後的參數是PropertyValuesHolder類的實例,可以有多個這樣的實例。代碼如下:
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("alpha", 1f, 0f, 1f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f);
PropertyValuesHolder pvhZ = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f);
ObjectAnimator.ofPropertyValuesHolder(view, pvhX, pvhY, pvhZ).setDuration(5000).start();

Animator監聽器
在很多時候,我們希望可以監聽到動畫的各種事件,比如動畫何時開始,何時結束,然後在開始或者結束的時候去執行一些邏輯處理。這個功能是完全可以實現的,Animator類當中提供了一個addListener()方法,這個方法接收一個AnimatorListener,我們只需要去實現這個AnimatorListener就可以監聽動畫的各種事件了。
大家已經知道,ObjectAnimator是繼承自ValueAnimator的,而ValueAnimator又是繼承自Animator的,因此不管是ValueAnimator還是ObjectAnimator都是可以使用addListener()這個方法的。另外AnimatorSet也是繼承自Animator的,因此addListener()這個方法算是個通用的方法。
添加一個監聽器的代碼如下所示:
private void AnimatorListener(View view){
    ObjectAnimator animator = ObjectAnimator.ofFloat(view, "rotation", 0f,360f);
    animator.setDuration(2000);
    //第一種監聽方式
    animator.addListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animator) {
            Log.e("ceshi", "Start");
        }

        @Override
        public void onAnimationEnd(Animator animator) {
            Log.e("ceshi",  "End");
        }

        @Override
        public void onAnimationCancel(Animator animator) {
            Log.e("ceshi", "Cancel");
        }

        @Override
        public void onAnimationRepeat(Animator animator) {
            Log.e("ceshi", "Repeat");
        }
    });
    animator.start();
    animator.setRepeatCount(2);
}
第二種監聽方式,利用Android提供了一個適配器類,叫作AnimatorListenerAdapter實現動畫的監聽,代碼如下:
//第二種方式,可以自定義加載監聽事件,利用適配器
animator.addListener(new AnimatorListenerAdapter() {
    @Override
    public void onAnimationEnd(Animator animation) {
        super.onAnimationEnd(animation);
    }
});

可以自定義監聽的方法,需要什麼就寫什麼。
日誌打印結果:


使用XML編寫屬性動畫
通過XML來編寫動畫可能會比通過代碼來編寫動畫要慢一些,但是在重用方面將會變得非常輕鬆,比如某個將通用的動畫編寫到XML裏面,我們就可以在各個界面當中輕鬆去重用它。
如果想要使用XML來編寫動畫,首先要在res目錄下面新建一個animator文件夾,所有屬性動畫的XML文件都應該存放在這個文件夾當中。然後在XML文件中我們一共可以使用如下三種標籤:
<animator>  對應代碼中的ValueAnimator
<objectAnimator>  對應代碼中的ObjectAnimator
<set>  對應代碼中的AnimatorSet
所有的都只需調用xml文件就好:
ObjectAnimator animator = (ObjectAnimator) AnimatorInflater.loadAnimator(getApplicationContext(),R.animator.object_animator);
animator.setTarget(view);
animator.start();
ValueAnimator:
valueFrom和valueTo分別是起始和終止的數值,valueType對應着ofFloat等;
<!--valueType對應着ofFloat ofInt ofObject-->
<animator xmlns:android="http://schemas.android.com/apk/res/android"
    android:valueFrom="0"
    android:valueTo="100"
    android:valueType="floatType"/>
ObjectAnimator:
其中propertyName是參數值可以是alpha也可以是scaleX等,跟java代碼實現差不多
<objectAnimator android:valueFrom="1"
    android:valueTo="0.5"
    android:valueType="floatType"
    android:propertyName="alpha"
    xmlns:android="http://schemas.android.com/apk/res/android" />
組合動畫:
ordering 有兩個選項:sequentially 和 together 。其中 together 爲默認項。
sequentially 表示 set 中的動畫,按照先後順序逐步進行(a 完成之後進行 b )。
together 表示set 中的動畫,在同一時間同時進行。
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:ordering="sequentially" >
<!--ordering 有兩個選項:sequentially 和 together 。其中 together 爲默認項。
sequentially 表示 set 中的動畫,按照先後順序逐步進行(a 完成之後進行 b )。
together 表示set 中的動畫,在同一時間同時進行。-->
    <objectAnimator
        android:duration="2000"
        android:propertyName="translationX"
        android:valueFrom="-200"
        android:valueTo="200"
        android:valueType="floatType" >
    </objectAnimator>

    <set android:ordering="together" >
        <objectAnimator
            android:duration="3000"
            android:propertyName="rotation"
            android:valueFrom="0"
            android:valueTo="360"
            android:valueType="floatType" >
        </objectAnimator>

        <set android:ordering="sequentially" >
            <objectAnimator
                android:duration="1500"
                android:propertyName="alpha"
                android:valueFrom="1"
                android:valueTo="0"
                android:valueType="floatType" >
            </objectAnimator>
            <objectAnimator
                android:duration="1500"
                android:propertyName="alpha"
                android:valueFrom="0"
                android:valueTo="1"
                android:valueType="floatType" >
            </objectAnimator>
        </set>
    </set>

</set>


效果與java代碼相同。


參考了大神的博客:http://blog.csdn.net/guolin_blog/article/details/43536355




源碼:下載




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章