Android:屬性動畫詳解

(一)簡介

屬性動畫是Android 3.0中提供了新功能,便於對任意元素進行“平滑的過渡”。衆所周知,Android 之前提供的補間動畫如AlphaAnimation、TranslateAnimation等都只能應用在View上,並且幾乎沒有任何可擴展的地方。並且,使用原來的動畫無法實現顏色漸變效果,算是一個遺憾。

屬性動畫徹底打破了這種設計方式,不再將這些動畫強制的放在View上,而是僅僅產生一系列的值,由開發人員自行使用這些值。例如,屬性動畫可產生1~0平滑過渡的值,把這些值應用在View的alpha上就可以實現透明度漸變了。

同時,屬性動畫可以直接用來改變View的屬性。例如,不斷的setTranslationX,便可實現水平方向的平移。

(二)代碼演示

1.ValueAnimator:產生某個範圍內平滑過渡的值。

//屬性動畫,0~1漸變
    public void simpleValueAnimator(View view) {
        ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
        anim.setDuration(300);
        //動畫過程的監聽
        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //回調方法在主線程執行
                float currentValue = (float) animation.getAnimatedValue();
                Log.d(TAG, "current value is " + currentValue);
            }
        });
        anim.start();
    }
(1)該方法可以通過設置多個值來實現更復雜的“平滑過渡”,例如實現0~5~3~10的過渡效果:
ValueAnimator anim = ValueAnimator.ofFloat(0f, 5f, 3f, 10f);
(2)設置啓動延時、重複次數、重複模式:

//設置啓動延時
        anim.setStartDelay(1000);
        //設置重複次數(也可以設置成無限次數)
        anim.setRepeatCount(3);
        //設置重複模式:重新執行動畫(也可以設置成倒序)
        anim.setRepeatMode(ValueAnimator.RESTART);
(3)監聽動畫開始、結束、重複狀態:

//監聽動畫的狀態(開始/結束/重複/取消)
        anim.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationStart(Animator animation) {
                super.onAnimationStart(animation);
                Log.d(TAG, "onAnimationStart");
            }

            @Override
            public void onAnimationRepeat(Animator animation) {
                super.onAnimationRepeat(animation);
                Log.d(TAG, "onAnimationRepeat");
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                Log.d(TAG, "onAnimationEnd");
            }
        });
2.ObjectAnimator:平滑的改變任意對象的屬性值。

(1)平滑改變TextView的不透明度:

public void changeAlphaValue(View view) {
        TextView textView = (TextView) findViewById(R.id.main_text1);
        //ObjectAnimator繼承自ValueAnimator
        //animator會調用textView的setAlpha方法。如果該方法不存在則會出現警告異常。
        ObjectAnimator animator = ObjectAnimator.ofFloat(textView, "alpha", 1f, 0f, 1f);
        animator.setDuration(3000);
        animator.start();
    }
該動畫並非直接改變textView的alpha屬性(事實上,textView甚至它的父組件View都沒有alpha屬性),而是調用textView的setAlpha方法,然後傳入1~0~1平滑漸變的值作爲參數,從而實現了不透明度漸變效果。

類似的,可以通過傳遞參數rotation、translationX(translationY)等實現旋轉、平移等效果。

3.使用AnimatorSet將各個動畫進行組合:

public void animatorSet(View view) {
        TextView textView = (TextView) findViewById(R.id.main_text1);
        ObjectAnimator moveIn = ObjectAnimator.ofFloat(textView, "translationX", -500f, 0f);
        ObjectAnimator rotate = ObjectAnimator.ofFloat(textView, "rotation", 0f, 360f);
        ObjectAnimator fadeInOut = ObjectAnimator.ofFloat(textView, "alpha", 1f, 0.2f, 1f);

        //先平移,然後在旋轉的同時進行alpha漸變
        AnimatorSet animSet = new AnimatorSet();
        animSet.play(rotate).with(fadeInOut).after(moveIn);
        animSet.setDuration(5000);
        animSet.start();
    }
animSet.play會產生一個Animator.Builder對象,然後可以使用with,after,before等方法進行動畫疊加。

4.自定義Evaluator,實現任意兩個對象之間的“平滑過渡”。

ValueAnimator的ofInt,ofFloat方法很簡單,無非是產生一些平滑過渡的數值。不過,ValueAnimator還有一個ofObject方法,可以實現兩個Object之間的平滑過渡。顯然,系統不可能知道應該怎麼過渡,因此需要我們指定它。

例如定義了一個類表示點的座標:

public class PointBean {
    private float x;
    private float y;

    public PointBean(float x, float y) {
        this.x = x;
        this.y = y;
    }

    public float getX() {
        return x;
    }

    public void setX(float x) {
        this.x = x;
    }

    public float getY() {
        return y;
    }

    public void setY(float y) {
        this.y = y;
    }
}
然後,我們希望實現兩個點之間的平滑過渡(通過它就可以實現View的平移了),就需要定義兩個PointBean之間是如何過渡的。當然此處的實現很簡單:

public class PointEvaluator implements TypeEvaluator<PointBean> {
    @Override
    public PointBean evaluate(float fraction, PointBean startValue, PointBean endValue) {
        float x = startValue.getX() + fraction * (endValue.getX() - startValue.getX());
        float y = startValue.getY() + fraction * (endValue.getY() - startValue.getY());
        return new PointBean(x, y);
    }
}
參數fraction表示動畫完成度(0.0~1.0的一個值),startValue表示開始點,endValue表示結束點,該方法需要返回從startValue過渡到endValue、完成比例是fraction時的結果。
然後,通過兩個PointBean的過渡實現平移效果(此處僅爲示意,實際場景中可以直接使用ObjectAnimator):

ValueAnimator animator = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);
        animator.setDuration(2000);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                PointBean current = (PointBean) animation.getAnimatedValue();
                imageView.setTranslationX(current.getX());
                imageView.setTranslationY(current.getY());
            }
        });
        animator.start();
5.實現顏色漸變

與上述內容相似,實現紅色~綠色~藍色的漸變:

ValueAnimator animator = ValueAnimator.ofObject(new ColorEvaluator(), "#ffff0000", "#ff00ff00", "#ff0000ff");
        animator.setDuration(5000);

        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                String currentColor = (String) animation.getAnimatedValue();
                textView.setBackgroundColor(Color.parseColor(currentColor));
            }
        });
        animator.start();
顯然此處的重點是ColorEvaluator,即指定顏色值是如何漸變的。例如, #ffff0000是如何過渡到#ff00ff00的。
public class ColorEvaluator implements TypeEvaluator<String> {
    //僅支持AARRGGBB模式
    @Override
    public String evaluate(float fraction, String startValue, String endValue) {
        if (!startValue.startsWith("#") || !endValue.startsWith("#")) {
            throw new IllegalArgumentException("color must started with '#'.");
        }

        if (startValue.length() != 9 || endValue.length() != 9) {
            throw new IllegalArgumentException("startValue and endValue must be '#AARRGGBB'.");
        }

        int start_a, start_r, start_g, start_b;
        int end_a, end_r, end_g, end_b;

        //start
        start_a = getIntValue(startValue, 1, 3);
        start_r = getIntValue(startValue, 3, 5);
        start_g = getIntValue(startValue, 5, 7);
        start_b = getIntValue(startValue, 7, 9);

        //end
        end_a = getIntValue(endValue, 1, 3);
        end_r = getIntValue(endValue, 3, 5);
        end_g = getIntValue(endValue, 5, 7);
        end_b = getIntValue(endValue, 7, 9);

        return "#" + getHexString((int) (start_a + fraction * (end_a - start_a)))
                + getHexString((int) (start_r + fraction * (end_r - start_r)))
                + getHexString((int) (start_g + fraction * (end_g - start_g)))
                + getHexString((int) (start_b + fraction * (end_b - start_b)));
    }

    //從原始#AARRGGBB顏色值中指定位置截取,並轉爲int.
    private int getIntValue(String hexValue, int start, int end) {
        return Integer.parseInt(hexValue.substring(start, end), 16);
    }

    private String getHexString(int value) {
        String a = Integer.toHexString(value);
        if (a.length() == 1) {
            a = "0" + a;
        }

        return a;
    }
}
6.設置Interpolator,控制動畫進行的方式,如勻速、逐漸加速、逐漸減速或先加速後減速等效果。此處和傳統的動畫很相似。同樣,可以自定義Interpolator的實現。

anim.setInterpolator(new AccelerateInterpolator());  //逐漸加速的動畫
7.ViewPropertyAnimator:使用屬性動畫爲View設置動畫效果的一種簡便方式。

testImageView.animate().setDuration(2000).alpha(0.3f).rotationBy(360).yBy(160);
上述代碼表示將testImageView的不透明度漸變至0.3,同時旋轉360度、向下移動160px。

這裏的方法都有兩種形式,如rotation(360)表示旋轉至360度的位置(不管起始狀態是多少度,都旋轉至360度),而rotationBy(360)表示旋轉360度(如果起始位置不是0度,則結束時依然不是0度)。








發佈了114 篇原創文章 · 獲贊 24 · 訪問量 49萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章