標籤雲

搜尋此網誌

2013/06/28

Animation - Property Animations

上一篇整理了 android.view.animation 下的基本補間動畫
及逐格動畫
但是由於 View Animation 必須作用在 View 上而且只有四種受限的動畫效果
所以其實並不是太好用

API level 11 新增的 Property Animation 則沒有上述的限制
適用於 View 和 非View 的物件,而且物件本身的屬性會確實被修改
舉凡顏色、位置、尺寸等都可以控制

Property Animation 相關的類別幾乎都在 android.animation 這個 package
這其中包含三種角色:Animators, Evaluators, Interpolators

Animators
Animator, ValueAnimator, ObjectAnimator 這幾個家族成員

它們的繼承關係架構如下:
java.lang.Object
 ↳ android.animation.Animator
    ↳ android.animation.ValueAnimator
       ↳ android.animation.ObjectAnimator
Animator 負責動畫的基本架構的一個類別,通常我們不直接使用
ValueAnimator 是一個計時引擎也負責計算屬性值
它有一個 addUpdateListener(ValueAnimator.AnimatorUpdateListener listener) 的方法
可以讓我們在動畫進行時接收到屬性的變化
而大多數情況下我們使用 ObjectAnimator 因為它比較易於操作

另外負責將動畫組合的類別 android.animation.AnimatorSet 也是繼承自 Animator

Evaluators
Evaluators 是負責告訴 Animator 要如何計算屬性值
當然所需的屬性資料也是由 Animator 來提供
基本上看名稱就可以知道要用哪一個:

IntEvaluator - 當屬性值是 int 時使用 IntEvaluator
FloatEvaluator - 當屬性值是 float 時使用 FloatEvaluator
ArgbEvaluator - 當屬性值是色碼值 ARGB 時使用 ArgbEvaluator
TypeEvaluator - 如果不是以上三種,可能就要自訂 Evaluator,而方式就是實作 TypeEvaluator 這個 interface,而實作的方法可以參考官方文章 Using a TypeEvaluator

Interpolators
Interpolator 定義動畫的線性類型是定速、加速、減速 或先加速後減速之類
也是看名稱就可以猜出功能
AccelerateDecelerateInterpolator - 先加速後減速
AccelerateInterpolator - 加速
AnticipateInterpolator - 先往後再往前
AnticipateOvershootInterpolator - 先往後再超過再回來
BounceInterpolator - 反彈
CycleInterpolator - 週期性重複
DecelerateInterpolator - 減速
LinearInterpolator - 定速
OvershootInterpolator - 超過再回來
TimeInterpolator - 實作 TimeInterpolator 這個 interface 來自訂 Interpolator

接著來看看簡單範例:(修改自 DevBytes: Property Animations)

//static ObjectAnimator  ofFloat(Object target, String propertyName, float... values)
//property 參數要放屬性名稱,但該屬性要有相對應的setter & getter (例如屬性名稱是"alpha"那就要有 setAlpha(), getAlpha())
// ObjectAnimator android.animation.ObjectAnimator.ofFloat(View target, Property property, float... values)
// API 14 之後改成可以使用常數設定 property 參數,如本例為View.TRANSLATION_X,型別為 Property 這樣更易使用
ObjectAnimator translateAnimation =
    ObjectAnimator.ofFloat(translateButton, View.TRANSLATION_X, 800);
translateAnimation.setRepeatCount(1);
translateAnimation.setRepeatMode(ValueAnimator.REVERSE); //repeatMode 的預設值是 RESTART
//可以注意到這邊我們並沒有呼叫 setDuration 去設定動畫時間
//因為在 ObjectAnimator 裡有預設 duration 是 300 milliseconds

// 因為要同時控制 SCALE_X 跟 SCALE_Y 兩個屬性,所以這邊要用 PropertyValuesHolder 來控制
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat(View.SCALE_X, 2);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat(View.SCALE_Y, 2);
ObjectAnimator scaleAnimation =
    ObjectAnimator.ofPropertyValuesHolder(scaleButton, pvhX, pvhY);
scaleAnimation.setRepeatCount(1);
scaleAnimation.setRepeatMode(ValueAnimator.REVERSE);

// AnimatorSet 的用法
AnimatorSet animationSet = new AnimatorSet();
animationSet.play(animation2_1).after(animation1).before(animation3);
animationSet.play(animation2_2).before(animation3); 
//注意:這樣寫只能保證animation2_2先於animation3
//不能保證animation2_2與animation1或animation2_1的先後
//老實說這設定方式有點怪,不如使用 xml 來設定順序

//最後呼叫 start() 開始播放
animationSet.start();

另外一樣也可以用 xml 的方式來設定動畫
但是 Property Animation 的檔案應該放在 res/animator/ 資料夾下
跟 View Animation 是不同的,記得別放錯哦

簡單範例如下:


    <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
        android:propertyName="alpha"
        android:repeatCount="1"
        android:repeatMode="reverse"
        android:duration="300"
        android:valueTo="0"/>

    
        <objectAnimator
            android:propertyName="scaleX"
            android:repeatCount="1"
            android:repeatMode="reverse"
            android:duration="300"
            android:valueTo="2"/>
        <objectAnimator
            android:propertyName="scaleY"
            android:repeatCount="1"
            android:repeatMode="reverse"
            android:duration="300"
            android:valueTo="2"/>
    


若來源是 xml 一樣要先取得 Animator 才能 start
Animator anim = AnimatorInflater.loadAnimator(this, animationID);
anim.setTarget(view);
anim.start();

更新:
在 DevBytes: Bounce Animations 的範例中
示範了一個反彈範例
我們可以從其中 MyView 的 code 裡面比較一下 ValueAnimator 跟 ObjectAnimator 的寫法
//ValueAnimator
ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
anim.addUpdateListener(new AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        setShapeY((int) (animation.getAnimatedFraction() * (getHeight() - mShapeH)));
    }
});
anim.setRepeatCount(ValueAnimator.INFINITE);
anim.setRepeatMode(ValueAnimator.REVERSE);
anim.setInterpolator(new AccelerateInterpolator()); //在 REVERSE 時加速也會是 REVERSE
anim.start();

//ObjectAnimator 
ObjectAnimator anim = ObjectAnimator.ofInt(this, "shapeY", 0, (getHeight() - mShapeH)); 
//與 ValueAnimator 不同,不用 addUpdateListener 去每次設定值,ObjectAnimator 幫我們做好了
anim.setRepeatCount(ValueAnimator.INFINITE);
anim.setRepeatMode(ValueAnimator.REVERSE);
anim.setInterpolator(new AccelerateInterpolator());
anim.start();

相關資料:
YouTube - DevBytes: Property Animations
YouTube - DevBytes: Bounce Animations

developer.android.com - Property Animation
developer.android.com - ObjectAnimator
developer.android.com - ValueAnimator

沒有留言: