Android 屬性動畫 詳解

Android 屬性動畫 詳解

Android動畫類型:
View Animation(即所謂的Tween Animation補間動畫):View Animation相當簡單,不過只能支持簡單的縮放、平移、旋轉、透明度基本的動畫
Drawable Animation (即所謂Frame Animation逐幀動畫)
Property Animation 利用對象的屬性變化形成動畫的效果
Tween Animation和Frame Animation的動態效果只適應一個控件,或者說多個控件同時執行一種效果。
Property Animation可同時對一個對象應用多個動畫,動畫期間可以進行交互設置。

Property Animation 和 View Animation的區別
1、View Animation只能用於View及View的子類的對象;Property Animation則沒有這樣的限制
2、View Animation限制較多,一些動畫,只能用於沒有background的view,否則會打不到預期效果;如縮放一個view時,這是縮小了view的外觀,她的background並沒有改變,所以如果background不是透明的,則會露餡。
3、View Animation只是簡單的改變View的繪製,並不會改變View本身。比如,你將一個button從位置1移動到位置2,但是觸發點擊事件的位置還是在位置1。Property Animation這不會出現這種情況。
View Animation使用的代碼較少,啓動所花費的時間也短

PropertyAnimation
屬性動畫,就是利用對象的屬性變化形成動畫的效果。
屬性動畫的類可以用Animator這個抽象類來表示,通常使用它的子類:AnimatorSet和ValueAnimator,
同時ValueAnimator有兩個子類分別是ObjectAniamtor和TimeAnimator。

1、定義屬性動畫的XML資源的時候通常可以是如下三個元素之一作爲根元素:
<set>元素:
—該資源元素代表的是AniamtorSet類:動畫集合,即同時對一個對象應用多個動畫,這些動畫可以同時播放也可以對不同動畫設置不同的延遲
這個類可以包含<set>,<objectAniamtor>, <animator>三個子元素。
<objectAnimator>元素:
—用於定義objectAniamtor類,一個對象的一個屬性動畫。
<animator>元素:
—用於定義ValueAnimator類,在一個特定的時間裏執行一個動畫。
<set> <objectAniamtor> <animator>定義此三種元素的xml文件必須位於res/animator目錄下

<set android:ordering="[together|sequentially]"> // 控制子動畫啓動順序:默認(together)同時啓動,sequentially按先後順序啓動
    <objectAnimator
        android:propertyName="string" 
        //要執行動畫的屬性名,如"alpha" "backgroundColor" 
        android:duration="int"   
        //int型,動畫的持續時間,單位毫秒,默認爲300毫秒
        android:valueFrom="float|int|color" //float int color類型,動畫的起始點,若沒有指定,系統會通過屬性的get方法獲取,顏色爲6位十六進制的數字表示
        android:valueTo="float|int|color"
//float int color類型,必須設置的節點屬性,表明動畫的結束點,如果是顏色的話,由6位十六進制的數字表示
        android:startOffset="int" 
//int型,動畫延遲時間,從調用start方法後開始計算,單位毫秒
        android:repeatCount="int" 
//int型,動畫重複次數,默認爲0,不重複執行,"-1"無線循環,"1"動畫執行完後再重複執行一次
        android:interpolator="" 
//定義動畫變化速率的接口,所有插值器都必須實現此接口,如線性、非線性插值器
        android:repeatMode="[reapeat|reverse]" // int型,重複模式,該值必須爲正數或-1,"reverse"動畫向相反的方向執行、"repeat"動畫每次都從頭開始循環
        android:valueType="[intType|floatType]"/> // intType和floatType兩種:分別說明動畫值爲int和float型,若value是一個顏色,就不需指定,動畫框架會自動處理顏色值
    <animator      
        android:duration="int"
        android:valueFrom="float|int|color"
        android:valueTo="float|int|color"
        android:startOffset="int"
        android:repeatCount="int"
        android:interpolator=""
        android:repeatMode="[reapeat|reverse]"
        android:valueType="[intType|floatType]"/>
    <set>
        ....
    </set>    
</set>

//示例
//res/animator/animSet.xml

<set xmlns:android="http://schemas.android.com/apk/res/android"  
    android:ordering="sequentially" >  
    <objectAnimator  
        android:duration="2000"  
        android:propertyName="translationX"  
        android:valueFrom="-500"  
        android:valueTo="0"  
        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> 

//代碼訪問

Animator animator = AnimatorInflater.loadAnimator(context, R.animator.animSet);  
animator.setTarget(view);  
animator.start();  

ValueAnimator
屬性動畫中的時間驅動,管理着動畫時間的開始、結束屬性值,相應時間屬性值計算方法等。
包含所有計算動畫值的核心函數以及每一個動畫時間節點上的信息、一個動畫是否重複、是否監聽更新事件等,並且還可以設置自定義的計算類型。
ValueAnimator有工廠方法ofInt()、ofFloat()、ofObject()用於不同的類型

ValueAnimator animator = ValueAnimator.ofFloat(0, mContentHeight);  
animator.setTarget(view);   //設置作用目標
animator.setDuration(5000).start();
//ValueAnimator.AnimatorUpdateListener
animator.addUpdateListener(new AnimatorUpdateListener() { // ValueAnimator沒有設置屬性,需要通過updateListener裏設置屬性纔會生效。
    @Override
    public void onAnimationUpdate(ValueAnimator animation){ 
    //通過當前動畫的計算去修改任何屬性 ,幀刷新時調用,用於使用ValueAnimator計算出的屬性值
        float value = (float) animation.getAnimatedValue();
        view.setXXX(value);  //必須通過這裏設置屬性值纔有效,ValueAnimator不直接操作屬性值,所以要操作對象的屬性可以不需要setXXX與getXXX方法
        view.mXXX = value;  //不需要setXXX屬性方法
    }
});

ObjectAnimator
1、繼承自ValueAnimator,允許你指定要進行動畫的對象以及該對象的一個屬性。該類會根據計算得到的新值自動更新屬性(不同於ValueAnimator,ValueAnimator需另寫動畫更新邏輯),
2、ObjectAnimator使用有一定的限制,它需要目標對象的屬性提供指定的處理方法(譬如提供getXXX,setXXX方法)。
3、ObjectAnimator類提供了ofInt、ofFloat、ofObject這個三個常用的方法,這些方法都是設置動畫作用的元素、屬性、開始、結束等任意屬性值,
當屬性值(上面方法的參數)只設置一個時就把通過getXXX反射獲取的值作爲起點,設置的值作爲終點;如果設置兩個(參數),那麼一個是開始、另一個是結束。
ObjectAnimator的動畫原理是不停的調用setXXX方法更新屬性值,所有使用ObjectAnimator更新屬性時的前提是Object必須聲明有getXXX和setXXX方法。
通常使用ObjectAnimator設置View已知的屬性來生成動畫,而一般View已知屬性變化時都會主動觸發重繪圖操作,所以動畫會自動實現
使用示例:
a: xml + 代碼
//res/animator/objectColor => ObjectAnimator xml設置

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="5000"
    android:propertyName="backgroundColor"
    android:repeatCount="infinite"
    android:repeatMode="reverse"
    android:valueFrom="#ff8080"
    android:valueTo="#8080ff"
    android:valueType="intType" >
</objectAnimator>

//ObjectAnimator操作代碼

ObjectAnimator oa = (ObjectAnimator) AnimatorInflater.loadAnimator(this, R.animator.objectColor); /加載屬性動畫需要用到AnimatorInflater類
oa.setEvaluator(new ArgbEvaluator()); //用於動畫計算的需要,如果開始和結束的值不是基本類型的時候,這個方法是需要的。
oa.setTarget(imageView); //設置動畫的設置目標
oa.start();

//res/animator/objectScale => ObjectAnimator xml設置

<?xml version="1.0" encoding="utf-8"?> 
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" 
    android:duration="1000" 
    android:propertyName="scaleX"  
    android:valueFrom="1.0" 
    android:valueTo="2.0" 
    android:valueType="floatType"> 
</objectAnimator> 

//ObjectAnimator操作代碼
Animator anim = AnimatorInflater.loadAnimator(this,R.animator.objectScale); 
anim.setTarget(view); 
anim.start(); 

b:純代碼定義、使用

ObjectAnimator.ofFloat(view, "rotationY", 0.0f, 360.0f).setDuration(1000).start();
float curTranslationX = textview.getTranslationX();  
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "translationX", curTranslationX, -500f, curTranslationX);  
//ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "scaleY", 1f, 3f, 1f); 
animator.setDuration(5000);  
animator.start();  
ObjectAnimator mObjectAnimator= ObjectAnimator.ofInt(view, "customerDefineAnyThingName", 0,  1) .setDuration(2000);

//若Object不是View,或者設置的屬性沒有觸發重繪,或者在重繪時需要做自己的操作,則可以通過addUpdateListener()方法添加AnimatorUpdateListener監聽:
mObjectAnimator.addUpdateListener(new AnimatorUpdateListener() {
     @Override
     public void onAnimationUpdate(ValueAnimator animation) {
         //int value = animation.getAnimatedValue();  可以獲取當前屬性值
         //view.postInvalidate();  可以主動刷新
         //view.setXXX(value);
         //view.setXXX(value);
         //......可以批量修改屬性
     }
});

ObjectAnimator anim = ObjectAnimator.ofFloat(view, "op", 1.0F,  0.0F).setDuration(500); // "op", 設置的屬性不會觸發重繪
anim.start();  
anim.addUpdateListener(new AnimatorUpdateListener()  {   
     @Override  
     public void onAnimationUpdate(ValueAnimator animation)  {  //動畫更新監聽事件中,對view進行操作,觸發view的重繪
         float cVal = (Float) animation.getAnimatedValue();  
         view.setAlpha(cVal);  
         view.setScaleX(cVal);  
         view.setScaleY(cVal);  
     }  
});

PropertyValuesHolder
多屬性動畫同時工作管理類。有時候我們需要同時修改多個屬性,那就可以用到此類–針對同一個對象的多個屬性,要同時作用多種動畫。
ValueAnimator和ObjectAnimator的ofPropertyValuesHolder(view,…)可實現多屬性動畫

//平移的過程中同時改變XY軸的縮放,
PropertyValuesHolder pvh1 = PropertyValuesHolder.ofFloat("translationX", 300); 
PropertyValuesHolder pvh2 = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f); 
PropertyValuesHolder pvh3 = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f); 
ObjectAnimator.ofPropertyValuesHolder(view, pvh1, pvh2, pvh3).setDuration(1000).start(); //可以實現同時修改多個屬性的動畫
//移動過程中漸進顯示
PropertyValuesHolder a1 = PropertyValuesHolder.ofFloat("alpha", 0f, 1f);
PropertyValuesHolder a2 = PropertyValuesHolder.ofFloat("translationY", 0, viewWidth);
......
ObjectAnimator.ofPropertyValuesHolder(view, a1, a2, ......).setDuration(1000).start(); // 可以實現同時修改多個屬性的動畫

AnimatorSet
對於一個對象同時作用多個屬性動畫效果,同時也能實現更爲精確的順序控制。

ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView, "translationX", 300f); 
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(imageView, "scaleX", 1f, 0f, 1f); 
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(imageView, "scaleY", 1f, 0f, 1f); 
AnimatorSet animatorSet = new AnimatorSet(); 
animatorSet.setDuration(1000); 
animatorSet.playTogether(objectAnimator, objectAnimator1, objectAnimator2); 
//animatorSet.play(objectAnimator).with(objectAnimator1);  
//animatorSet.play(objectAnimator1).with(objectAnimator2);       
animatorSet.start();  

ObjectAnimator moveIn = ObjectAnimator.ofFloat(textview, "translationX", -500f, 0f);  
ObjectAnimator rotate = ObjectAnimator.ofFloat(textview, "rotation", 0f, 360f);  
ObjectAnimator fadeInOut = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);  
AnimatorSet animSet = new AnimatorSet();  
animSet.play(rotate).with(fadeInOut).after(moveIn);  
animSet.setDuration(5000);  
animSet.start();

在屬性動畫中,AnimatorSet正是通過playTogether()、playSquentially()、play().width()、play().defore()、play().after()支持鏈式編程這些方法來控制多個動畫的協同工作方式,從而做到對動畫播放順序的精確控制。

AnimatorListener / AnimatorListenerAdapter
一個完整的動畫具有Start、Repeat、End、Cancel四個過程,動畫事件的監聽:通過Android接口AnimatorListener,AnimatorListenerAdapter:

ObjectAnimator anim = ObjectAnimator.ofFloat(imageView, "alpha", 0.5F); 
anim.addListener(new Animator.AnimatorListener() { 
    @Override 
    public void onAnimationStart(Animator animation) { 
    } 
    @Override 
    public void onAnimationEnd(Animator animation) { 
    } 
    @Override 
    public void onAnimationCancel(Animator animation) { 
    } 
    @Override 
    public void onAnimationRepeat(Animator animation) { 
    } 
}); 
或使用AnimatorListenerAdapter,AnimatorListenerAdapter使用空方法實現了AnimatorListener的所有方法
anim.addListener(new AnimatorListenerAdapter() { 
    @Override 
    public void onAnimationEnd(Animator animation) {
        super.onAnimationEnd(animation); 
    } 
});
anim.start();  

Evaluators
Evaluators就是屬性動畫系統如何去計算一個屬性值。它們通過Animator提供的
動畫的起始和結束值去計算一個動畫的屬性值。
IntEvaluator: 整數屬性值。
FloatEvaluator:浮點數屬性值。
ArgbEvaluator: 十六進制color屬性值。
TypeEvaluator: 用於定義屬性值計算方式的接口,有int、float、color類型,根據屬性的起始、結束值和插值一起計算出當前時間的屬性值
//TypeEvaluator接口代碼

public interface TypeEvaluator<T> {
    //根據動畫進度,屬性起始值和結束值,計算出當前值
    public T evaluate(float fraction, T startValue, T endValue);
}

Interpolators
插值器可以定義動畫變換速率,主要是控制目標變量的值進行對應的變化。
AccelerateDecelerateInterpolator —先加速後減速,在動畫開始與結束的地方速率改變比較慢,在中間的時候加速
AccelerateInterpolator —加速,在動畫開始的地方速率改變比較慢,然後開始加速
DecelerateInterpolator —減速,在動畫開始的地方快然後慢
AnticipateInterpolator —先向相反方向改變一段再加速播放
AnticipateOvershootInterpolator —先向相反方向改變,再加速播放,會超出目標值然後緩慢移動至目標值,類似於彈簧回彈
BounceInterpolator —動畫結束的時候彈起,快到目標值時值會跳躍
CycleInterpolator —動畫循環播放特定的次數,速率改變沿着正弦曲線,值的改變爲一正弦函數:Math.sin(2 * mCycles * Math.PI * input)
LinearInterpolator —以常量速率改變,線性均勻改變
OvershootInterpolator —最後超出目標值然後緩慢改變到目標值,類似彈簧效果
PathInterpolator —路徑插值器
TimeInterpolator:一個允許自定義Interpolator的接口,以上都實現了該接口

使用示例:

ValueAnimator valueAnimator = new ValueAnimator();
valueAnimator.setDuration(5000);
valueAnimator.setObjectValues(new float[2]); //設置屬性值類型
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.setEvaluator(new TypeEvaluator<float[]>() {
    @Override
    public float[] evaluate(float fraction, float[] startValue,float[] endValue)
    {
        //實現自定義規則計算的float[]類型的屬性值
        float[] temp = new float[2];
        temp[0] = fraction * 2;
        temp[1] = (float)Math.random() * 10 * fraction;
        return temp;
    }
});
valueAnimator.start();
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        float[] xyPos = (float[]) animation.getAnimatedValue();
        view.setHeight(xyPos[0]);   //通過屬性值設置View屬性動畫
        view.setWidth(xyPos[1]);    //通過屬性值設置View屬性動畫
    }
});

Keyframes關鍵幀
一個Keyframe對象有一個time/value對組成,用於指定在特定時間點,動畫的狀態。每一個關鍵幀都可以有它自己的插值器,用來控制前一個關鍵幀和此關鍵幀的關係。
1、使用方法ofInt(), ofFloat(), 和ofObject()中的一個來獲得一個關鍵幀實例。
2、然後調用PropertyValuesHolder的工廠方法ofKeyframe()來獲得一個PropertyValuesHolder對象。
3、將PropertyValuesHolder對象作爲ObjectAnimator.ofPropertyValuesHolder()方法的參數,即可構造出一個對象。
示例

Keyframe kf0 = Keyframe.ofFloat(0f, 0f);
Keyframe kf1 = Keyframe.ofFloat(.5f, 360f);
Keyframe kf2 = Keyframe.ofFloat(1f, 0f);
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2);
ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation);
rotationAnim.setDuration(5000ms);

ViewPropertyAnimator
動畫是屬性動畫的拓展,在Android API 12中,View添加了animate方法,具體如下:

public class View implements Drawable.Callback, KeyEvent.Callback,AccessibilityEventSource {
    ...
    public ViewPropertyAnimator animate() {
        if (mAnimator == null) {
            mAnimator = new ViewPropertyAnimator(this); //當前視圖的視圖屬性動畫
        }
        return mAnimator;
    }
    ...
}

通過View的animate()方法可以得到一個ViewPropertyAnimator的屬性動畫,ViewPropertyAnimator提供了一種非常方便的方法爲View的部分屬性設置動畫,它可以直接使用一個Animator對象設置多個屬性的動畫;
在多屬性設置動畫時,它比上面的ObjectAnimator更加酷炫、高效,因管理多個屬性的invalidate方法統一調度、運行、觸發,而不像上面分別調用,所以還會有一些性能優化。

myView.animate().x(0f).y(100f).start();

myView.animate() // need API12 
      .alpha(0)
      .y(mScreenHeight / 2)
      .setDuration(1000)    
      .withStartAction(new Runnable() {  // need API 12 
          @Override
          public void run() { 
             Log.e(TAG, "START"); 
          } 
      })
      .withEndAction(new Runnable() {  // need API 16 
          @Override
          public void run()  { 
             Log.e(TAG, "END"); 
             runOnUiThread(new Runnable() { 
                @Override
                public void run() { 
                   myView.setY(0); 
                   myView.setAlpha(1.0f); 
                } 
             }); 
          } 
       }).start(); 

LayoutAnimation LayoutTransition佈局動畫
LayoutAnimation
LayoutAnimation它是用來控制ViewGroup中所有的child view顯示的動畫,使用方式: xml定義使用, 代碼定義方式
1、
a:LayoutAnimation動畫直接在xml中定義(res/anim/customer_anim.xml):
//res/anim/slide_right.xml

<set xmlns:android="http://schemas.android.com/apk/res/android"   
        android:interpolator="@android:anim/accelerate_interpolator">  
    <translate android:fromXDelta="-100%p" android:toXDelta="0"  
            android:duration="@android:integer/config_shortAnimTime" />  
</set>

//res/animator/layout_anim.xml

<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"  
    android:delay="30%"   //動畫播放的延時,可以是百分比,也可以是float小數,其中delay的單位爲秒
    android:animationOrder="reverse"  //動畫的播放順序,有三個取值normal(0,順序)、reverse(1,反序)、random(2,隨機)
    android:animation="@anim/slide_right"/> //指向子控件所要播放的動畫(表示孩子顯示時的具體動畫)

b:在ViewGroup的layout xml文件中設置:

<ListView...
    android:layoutAnimation="@animator/layout_anim"/>

2、代碼中使用:
//ScaleAnimation sa = new ScaleAnimation(0, 1, 0, 1);
//sa.setDuration(2000);
//LayoutAnimationController controller = new LayoutAnimationController(sa, 0.5f); //設置佈局動畫的顯示
//LayoutAnimationController 的第一個參數,是需要作用的動畫,而第二個參數,則是每個子View顯示的delay時間

Animation animation = AnimationUtils.loadAnimation(this, R.anim.slide_right);   //得到一個LayoutAnimationController對象; 

//LayoutAnimationController可實現一個界面中的多個控件按照相同的動畫方式但是每個控件完成該動畫的時刻不同

LayoutAnimationController controller = new LayoutAnimationController(animation);   //設置控件顯示的順序;  
controller.setOrder(LayoutAnimationController.ORDER_REVERSE);   //設置控件顯示間隔時間;  
controller.setDelay(0.3);   //爲ListView設置LayoutAnimationController屬性;  
listView.setLayoutAnimation(controller);  
listView.startLayoutAnimation();  

public static final int ORDER_NORMAL = 0; //順序 
public static final int ORDER_REVERSE = 1; //反序 
public static final int ORDER_RANDOM = 2; //隨機 

LayoutTransition
LayoutTransition是從API Level 11出現的。LayoutTransition的動畫效果只有當ViewGroup中有View添加、刪除、隱藏、顯示的時候纔會體現出來。
它也有兩種使用方式: xml定義使用, 代碼定義方式
1、xml中使用系統默認的LayoutTransition動畫:

<LinearLayout android:id="@+id/container"
    android:animateLayoutChanges="true"
    ...
/> 

在ViewGroup添加如上xml屬性默認是沒有任何動畫效果的,當設置如上屬性,然後調用ViewGroup的addView、removeView方法時就能看見系統默認的動畫效果(即ViewGroup內部東東發生改變時纔有效)。

mContainer.addView(newView, 0);

2、代碼中使用LayoutTransition動畫:
LayoutTransition類中主要的五種容器轉換動畫類型,具體如下:
LayoutTransition.APPEARING — 當一個View在ViewGroup中出現時,對此View設置的動畫
LayoutTransition.CHANGE_APPEARING — 當一個View在ViewGroup中出現時,對此View對其他View位置造成影響,對其他View設置的動畫
LayoutTransition.DISAPPEARING — 當一個View在ViewGroup中消失時,對此View設置的動畫
LayoutTransition.CHANGE_DISAPPEARING — 當一個View在ViewGroup中消失時,對此View對其他View位置造成影響,對其他View設置的動畫
LayoutTransition.CHANGE — 不是由於View出現或消失造成對其他View位置造成影響,然後對其他View設置的動畫
注意:
動畫到底設置在誰身上,此View還是其他View

代碼中使用系統默認的LayoutTransition動畫

LayoutTransition mTransitioner = new LayoutTransition();  
mViewGroup.setLayoutTransition(mTransitioner);  

動畫使用示例:

private void setupCustomAnimations() {  
    LayoutTransition mTransitioner = new LayoutTransition(); 
    // 動畫:CHANGE_APPEARING  
    // Changing while Adding  
    PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left", 0, 1);  
    PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top", 0, 1);  
    PropertyValuesHolder pvhRight = PropertyValuesHolder.ofInt("right", 0, 1);  
    PropertyValuesHolder pvhBottom = PropertyValuesHolder.ofInt("bottom", 0, 1);  
    PropertyValuesHolder pvhScaleX = PropertyValuesHolder.ofFloat("scaleX", 1f, 0f, 1f);  
    PropertyValuesHolder pvhScaleY = PropertyValuesHolder.ofFloat("scaleY", 1f, 0f, 1f);  

    final ObjectAnimator changeIn = ObjectAnimator.ofPropertyValuesHolder(  
            this, pvhLeft, pvhTop, pvhRight, pvhBottom, pvhScaleX,  
            pvhScaleY).setDuration(mTransitioner.getDuration(LayoutTransition.CHANGE_APPEARING));  

    //通過使用LayoutTransition的方法setAnimator(),傳入一個Animator和一個LayoutTransition類中定義的五種容器轉換動畫類型之一,來定製用於ViewGroup的動畫       
    mTransitioner.setAnimator(LayoutTransition.CHANGE_APPEARING, changeIn);  
    changeIn.addListener(new AnimatorListenerAdapter() {  
        public void onAnimationEnd(Animator anim) {  
            View view = (View) ((ObjectAnimator) anim).getTarget();  
            view.setScaleX(1f);  
            view.setScaleY(1f);  
        }  
    });  

    // 動畫:CHANGE_DISAPPEARING  
    // Changing while Removing  
    Keyframe kf0 = Keyframe.ofFloat(0f, 0f);  
    Keyframe kf1 = Keyframe.ofFloat(.9999f, 360f);  
    Keyframe kf2 = Keyframe.ofFloat(1f, 0f);  
    PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2);  
    final ObjectAnimator changeOut = ObjectAnimator.ofPropertyValuesHolder(this, pvhLeft, pvhTop, pvhRight,  
                    pvhBottom, pvhRotation).setDuration(mTransitioner.getDuration(LayoutTransition.CHANGE_DISAPPEARING));  

    mTransitioner.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, changeOut);  
    changeOut.addListener(new AnimatorListenerAdapter() {  
        public void onAnimationEnd(Animator anim) {  
            View view = (View) ((ObjectAnimator) anim).getTarget();  
            view.setRotation(0f);  
        }  
    });  

    // 動畫:APPEARING  
    // Adding  
    ObjectAnimator animIn = ObjectAnimator.ofFloat(null, "rotationY", 90f, 0f).setDuration(mTransitioner.getDuration(LayoutTransition.APPEARING));  
    mTransitioner.setAnimator(LayoutTransition.APPEARING, animIn);  
    animIn.addListener(new AnimatorListenerAdapter() {  
        public void onAnimationEnd(Animator anim) {  
            View view = (View) ((ObjectAnimator) anim).getTarget();  
            view.setRotationY(0f);  
        }  
    });  

    // 動畫:DISAPPEARING  
    // Removing  
    ObjectAnimator animOut = ObjectAnimator.ofFloat(null, "rotationX", 0f, 90f).setDuration(mTransitioner.getDuration(LayoutTransition.DISAPPEARING));  
    mTransitioner.setAnimator(LayoutTransition.DISAPPEARING, animOut);  
    animOut.addListener(new AnimatorListenerAdapter() {  
        public void onAnimationEnd(Animator anim) {  
            View view = (View) ((ObjectAnimator) anim).getTarget();  
            view.setRotationX(0f);  
        }  
    });  

    mViewGroup.setLayoutTransition(mTransitioner);  

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