Android:属性动画详解

来源:互联网 发布:windows7乱码修复软件 编辑:程序博客网 时间:2024/04/28 03:51

(一)简介

属性动画是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度)。








0 0