1. 程式人生 > 其它 >Android 屬性動畫

Android 屬性動畫

技術標籤:# Android自定義View體系Animator

文章目錄

屬性動畫

概述

  • Android3.0之前的動畫框架存在一些缺陷,動畫改變的只是顯示,並不能響應事件。
  • 在Android3.0之後,谷歌推出全新的動畫框架,實現機制是通過對目標物件進行賦值並修改其屬性來實現的 。

ObjectAnimator

ObjectAnimator可以直接對任意物件的任意屬性進行動畫操作。

旋轉動畫

ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, ROTATION, 0f, 360f);
animator.setDuration(2000L);
animator.setRepeatCount(3);
animator.start();

平移動畫

float distance = imageView.getTranslationX();
ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, TRANSLATION_X, distance, 500, distance)
; animator.setDuration(2000L); animator.setRepeatCount(3); animator.start();

縮放動畫

ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, SCALE_Y, 1f, 3f, 1f);
animator.setDuration(2000L);
animator.start();

透明度動畫

ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, ALPHA, 1f, 0f, 1f);
animator.
setDuration(2000L); animator.start();

組合動畫

  • after(Animator anim) 將現有動畫插入到傳入的動畫之後執行
  • after(long delay) 將現有動畫延遲指定毫秒後執行
  • before(Animator anim) 將現有動畫插入到傳入的動畫之前執行
  • with(Animator anim) 將現有動畫和傳入的動畫同時執行
float distance = imageView.getTranslationX();
ObjectAnimator translation = ObjectAnimator.ofFloat(imageView, TRANSLATION_X, distance, 500, distance);
ObjectAnimator scale = ObjectAnimator.ofFloat(imageView, SCALE_Y, 1f, 3f, 1f);
ObjectAnimator rotation = ObjectAnimator.ofFloat(imageView, ROTATION, 0f, 360f);
ObjectAnimator alpha = ObjectAnimator.ofFloat(imageView, ALPHA, 1f, 0f, 1f);

AnimatorSet animatorSet = new AnimatorSet();
//1.同時執行動畫一
//        animatorSet.play(translation).with(scale).with(rotation).with(alpha);
//2.同時執行動畫二
//        animatorSet.playTogether(translation, scale, rotation, alpha);
//3.順序執行動畫
//        animatorSet.playSequentially(translation, scale, rotation, alpha);
//4.指定順序執行動畫:rotation->translation->scale
animatorSet.play(translation).before(scale).after(rotation);
animatorSet.setDuration(2000);
animatorSet.start();

ValueAnimator

  • ObjectAnimator類是屬性動畫中最核心的類,ObjectAnimator繼承於ValueAnimator
  • 屬性動畫是通過不斷修改值實現動畫效果,而初始值和結束值之間的變化由該類負責計算
//向右移動500
private void startValueAnimator() {
    int distance = 500;
    ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
    animator.setDuration(2000L);
    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            float value = (float) animation.getAnimatedValue();
            moveView(imageView, value, distance);
        }
    });
    animator.setInterpolator(new DecelerateInterpolator());
    animator.start();
}

private void moveView(View targetView, float value, int distance) {
    int left = rawLeft + (int) (value * distance);
    int top = targetView.getTop();
    int right = left + targetView.getWidth();
    int bottom = top + targetView.getHeight();
    targetView.layout(left, top, right, bottom);
}

TypeEvaluator 估值器

作用:設定屬性值從初始值過渡到結束值的變化具體數值

動畫的值 = 初始值 + 完成度 * (結束值 - 初始值)

實現了TypeEvaluator介面,然後重寫了evaluate()方法,引數有三個,依次是:

  • fraction:動畫的完成度,我們根據他來計算動畫的值應該是多少
  • startValue:動畫的起始值
  • endValue:動畫的結束值
private void startTypeEvaluator() {
    ValueAnimator valueAnimator = ValueAnimator.ofObject(new FloatEvaluator(), 0f, 1f);
    valueAnimator.setDuration(2000);
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            float value = (float) animation.getAnimatedValue();
            Log.e("TAG", "value:" + value);
        }
    });
    valueAnimator.start();
}

public class FloatEvaluator implements TypeEvaluator {
    public Object evaluate(float fraction, Object startValue, Object endValue) {
        float startFloat = ((Number) startValue).floatValue();
        return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);
    }
}

列印資訊

value:0.0
value:0.0
value:0.033116043
value:0.26119065
...
value:0.89794815
value:0.97329646
value:1.0

ViewPropertyAnimator

屬性動畫的機制已經不是再針對於View而進行設計的了,而是一種不斷地對值進行操作的機制,它可以將值賦值到指定物件的指定屬性上。但是,在絕大多數情況下,我相信大家主要都還是對View進行動畫操作的。Android開發團隊也是意識到了這一點,沒有為View的動畫操作提供一種更加便捷的用法確實是有點太不人性化了,於是在Android 3.1系統當中補充了ViewPropertyAnimator這個機制。

//透明度動畫
imageView.animate().alpha(0.5f).setDuration(2000L);
ViewCompat.animate(imageView).alpha(0.5f);

//平移動畫
imageView.animate().translationX(500f).setDuration(2000L);

//旋轉動畫
imageView.animate().rotation(360).setDuration(2000L);

//縮放動畫
imageView.animate().scaleX(1.5F).setDuration(2000L);

ObjectAnimator 高階用法

這裡寫圖片描述

public class MyAnimView extends View {
    public static final int RADIUS = 50;
    private Point currentPoint;
    private Paint mPaint;

    public MyAnimView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(Color.BLUE);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (currentPoint == null) {
            currentPoint = new Point(RADIUS, RADIUS);
            drawCircle(canvas);
            startAnimation();
        } else {
            drawCircle(canvas);
        }
    }

    private void drawCircle(Canvas canvas) {
        float x = currentPoint.x;
        float y = currentPoint.y;
        canvas.drawCircle(x, y, RADIUS, mPaint);
    }

    private void setColor(String color) {
        mPaint.setColor(Color.parseColor(color));
    }

    private void startAnimation() {
        Point startPoint = new Point(RADIUS, RADIUS);
        Point endPoint = new Point(getWidth(), getHeight());

        ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);
        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                currentPoint = (Point) animation.getAnimatedValue();
                invalidate();
            }
        });

        ObjectAnimator anim2 = ObjectAnimator.ofObject(this, "color", new ColorEvaluator(), "#0000FF", "#FF0000");
        anim2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                setColor((String) animation.getAnimatedValue());
                invalidate();
            }
        });

        AnimatorSet animSet = new AnimatorSet();
        animSet.play(anim).with(anim2);
        animSet.setDuration(5000);
        //速度加快
        //animSet.setInterpolator(new AccelerateInterpolator(2f));
        //彈跳效果
        animSet.setInterpolator(new BounceInterpolator());
        animSet.start();
    }

    public class PointEvaluator implements TypeEvaluator {

        @Override
        public Object evaluate(float fraction, Object startValue, Object endValue) {
            //fraction:動畫的完成度
            Point startPoint = (Point) startValue;
            Point endPoint = (Point) endValue;
            int x = (int) (startPoint.x + fraction * endPoint.x - startPoint.x);
            int y = (int) (startPoint.y + fraction * endPoint.y - startPoint.y);
            Point point = new Point(x, y);
            return point;
        }
    }

    public class ColorEvaluator implements TypeEvaluator {
        private int mRed = -1;
        private int mGreen = -1;
        private int mBlue = -1;

        @Override
        public Object evaluate(float fraction, Object startValue, Object endValue) {
            String startColor = (String) startValue;
            String endColor = (String) endValue;

            int startRed = Integer.parseInt(startColor.substring(1, 3), 16);
            int startGreen = Integer.parseInt(startColor.substring(3, 5), 16);
            int startBlue = Integer.parseInt(startColor.substring(5, 7), 16);
            int endRed = Integer.parseInt(endColor.substring(1, 3), 16);
            int endGreen = Integer.parseInt(endColor.substring(3, 5), 16);
            int endBlue = Integer.parseInt(endColor.substring(5, 7), 16);

            // 初始化顏色的值
            if (mRed == -1) {
                mRed = startRed;
            }
            if (mGreen == -1) {
                mGreen = startGreen;
            }
            if (mBlue == -1) {
                mBlue = startBlue;
            }

            // 計算初始顏色和結束顏色之間的差值
            int redDiff = Math.abs(startRed - endRed);
            int greenDiff = Math.abs(startGreen - endGreen);
            int blueDiff = Math.abs(startBlue - endBlue);
            int colorDiff = redDiff + greenDiff + blueDiff;

            if (mRed != endRed) {
                mRed = getCurrentColor(startRed, endRed, colorDiff, 0, fraction);
            } else if (mGreen != endGreen) {
                mGreen = getCurrentColor(startGreen, endGreen, colorDiff, redDiff, fraction);
            } else if (mBlue != endBlue) {
                mBlue = getCurrentColor(startBlue, endBlue, colorDiff, redDiff + greenDiff, fraction);
            }
            
            // 將計算出的當前顏色的值組裝返回
            String currentColor = "#" + getHexString(mRed) + getHexString(mGreen) + getHexString(mBlue);
            return currentColor;
        }

        /**
         * 根據fraction值來計算當前的顏色。
         */
        private int getCurrentColor(int startColor, int endColor, int colorDiff,
                                    int offset, float fraction) {
            int currentColor;
            if (startColor > endColor) {
                currentColor = (int) (startColor - (fraction * colorDiff - offset));
                if (currentColor < endColor) {
                    currentColor = endColor;
                }
            } else {
                currentColor = (int) (startColor + (fraction * colorDiff - offset));
                if (currentColor > endColor) {
                    currentColor = endColor;
                }
            }
            return currentColor;
        }

        /**
         * 將10進位制顏色值轉換成16進位制。
         */
        private String getHexString(int value) {
            String hexString = Integer.toHexString(value);
            if (hexString.length() == 1) {
                hexString = "0" + hexString;
            }
            return hexString;
        }
    }
}

程式碼下載