Android:Animator使用指南

本文是关于Android属性动画 Animator 的使用指南,从快速入门到颜色渐变动画的实现,详细介绍了TypeEvaluator如何帮助实现颜色平滑过渡,并探讨了PropertyValuesHolder作为包装器替代方案的优势。同时,文章还讨论了如何处理多对象动画和监听器的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(一)快速开始

Animator是属性动画,通过修改对象的属性来达到实现动画的效果。

一段替换Animation全功能的Animator代码:(请使用3.0以上API来执行前面的例子)

        ObjectAnimator animation = ObjectAnimator.ofFloat(view, "alpha", 0f, 1f);
//        ObjectAnimator animation = ObjectAnimator.ofFloat(view, "translationX", 0, 500);
//        ObjectAnimator animation = ObjectAnimator.ofFloat(view, "translationY", 0, 500);
//        ObjectAnimator animation = ObjectAnimator.ofFloat(view, "scaleX", 0, 2f);
//        ObjectAnimator animation = ObjectAnimator.ofFloat(view, "scaleY", 0, 2f);
//        ObjectAnimator animation = ObjectAnimator.ofFloat(view, "rotation", 0, 360f);
//        ObjectAnimator animation = ObjectAnimator.ofFloat(view, "rotationX", 0, 360f);
//        ObjectAnimator animation = ObjectAnimator.ofFloat(view, "rotationY", 0, 360f);
        animation.setDuration(5000);
        animation.start();

以上代码可以实现:透明度,位移,缩放,旋转变化

Animatoin中包含的锚点,可以直接对view进行设置:

        view.setPivotX(0);
        view.setPivotY(0);

虽然属性动画不太适合用XML书写,但是其Java代码的属性难度非常低,很容易理解。

(二)总体脉络

首先从实现一个颜色渐变的动画开始,讲述属性动画的属性是指什么,然后讲述一下如何使用TypeEvaluator。


(三) 颜色的渐变动画

当你想改变一个View的背景颜色的时候,你想到的方法是什么?

view.setBackgroundColor(color);

而对于属性动画而言,你指定一个属性之后,动画框架会反射的去调用你的setXXX来实现对你的属性的修改。

根据这个思路,我们将属性命名为backgroundColor ,于是写下下面的代码:

ObjectAnimator animation = ObjectAnimator.ofInt(view, "backgroundColor",0xffffffff, 0xff00ff00);
        animation.setDuration(5000);
        animation.start();

然后,你会发现屏幕很魔性的闪个不停,从一种颜色到另一种颜色。也就是说,我们确实成功的改变了视图的背景颜色,只是颜色的期望和我们想的不太一致。

因为使用RGB作为一个int值的时候,你对颜色的改变会使得blue不断的从0变成255,所以出现的效果很差。


(四)TypeEvaluator

所以你可能希望讲int值拆分成不同的a,r,g,b维度,分别对其进行变换。这样就使得各个颜色进行了均匀的变换。

这个时候你可以考虑用TypeEvaluator,它对你的初始值和最终值做一个变换模型,然后计算中间某一个进度对应的值。

        TypeEvaluator<Integer> colorTypeEvaluator = new TypeEvaluator<Integer>() {

            @Override
            public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
                int alpha = (int) (fraction * (Color.alpha(endValue) - Color.alpha(startValue)))
                        + Color.alpha(startValue);
                int red =  (int) (fraction * (Color.red(endValue) - Color.red(startValue)))
                        + Color.red(startValue);
                int green = (int) (fraction * (Color.green(endValue) - Color.green(startValue)))
                        + Color.green(startValue);
                int blue = (int) (fraction * (Color.blue(endValue) - Color.blue(startValue)))
                        + Color.blue(startValue);
                return Color.argb(alpha, red, green, blue);
            }
        };

例如:

ObjectAnimator animation = ObjectAnimator.ofObject(view, "backgroundColor",
                colorTypeEvaluator, 0xffffffff, 0xff00ff00);

的效果就是将颜色从白色慢慢的变成绿色,实现了我们的效果,非常的棒。


(五)颜色渐变的最终实现

但是,如果你想从红色变成绿色,并且中间颜色是过度的黄色。

        ObjectAnimator animation = ObjectAnimator.ofObject(view, "backgroundColor",
                colorTypeEvaluator, 0xffff0000, 0xff00ff00);

你会发现,在变换的过程中,并不会出现黄色,而是出现一种红不红绿不绿的奇怪颜色。

这是因为,你希望的是只是颜色色值发生变换,而饱和度和亮度都不要发生变化。

在这种情况下我们建议使用HSV颜色模型,而不是RGB颜色模型来进行过度。

【HSV请参考百度百科】

继续使用TypeEvaluator,同样只是对于值的映射有一些区别:

我们以HSV(colorStart)开始,以HSV(colorEnd)结束.

TypeEvaluator通过计算指定的开始数据与结束数据,然后得到中间的每一帧的数据。

        TypeEvaluator<Integer> colorTypeEvaluator = new TypeEvaluator<Integer>() {
            float[] hsvStart = null;
            float[] hsvEnd = null;

            @Override
            public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
                if (hsvStart == null) {
                    hsvStart = new float[3];
                    Color.colorToHSV(startValue, hsvStart);
                }
                if (hsvEnd == null) {
                    hsvEnd = new float[3];
                    Color.colorToHSV(endValue, hsvEnd);
                }

                float[] returnHsv = new float[hsvStart.length];
                for (int i = 0; i < hsvStart.length; i++) {
                    returnHsv[i] = hsvStart[i] + (hsvEnd[i] - hsvStart[i]) * fraction;
                }
                return Color.HSVToColor(returnHsv);
            }
        };


(六)再议属性动画

由于属性动画是对你的setXXX进行一个操作,所以,你可以考虑使用Wrapper的方式来实现多个值的同时修改。

Wrapper的动机是利用传入的参数的时机(set方法里),进行一些操作和处理,从而实现动画效果。

而它调用的方法是由你设置的属性("magic")和传入的类型(float)决定的。

    static class Wrapper{
        private View view;

        public Wrapper(View view) {
            this.view = view;
        }

        public void setMagic(float magic) {
            view.setRotation(magic);
            view.setRotationX(magic);
            view.setRotationY(magic);
        }
    }

调用代码:

ObjectAnimator animation = ObjectAnimator.ofFloat(new Wrapper(view), "magic", 0, 360f);

这样就实现了超级翻转(X,Y,Z同时翻转)。


(七)包装器的替代方案:PropertyValuesHolder

使用Wrapper的好处很明显,可以同时改变多个值,但是PropertyValuesHolder告诉你, I CAN DO IT (我能干IT)

对于ObjectAnimator而言,它有一个使用 进行静态构造的方法。

public static ObjectAnimator ofPropertyValuesHolder(Object target,
            PropertyValuesHolder... values) {

所以,我们需要构造PropertyValuesHolder对象。

PropertyValuesHolder有很多静态构造器,但是最简单好用的就是String propertyName那个.

例如,对于ofFloat而言:

public static PropertyValuesHolder ofFloat(String propertyName, float... values) 
便可以构造一个PropertyValuesHolder对象。


如果我们想做一个同时scaleX和scaleY的动画,可以使用下面的实现:

        PropertyValuesHolder holderX = PropertyValuesHolder.ofFloat("scaleX", 0f,1f);
        PropertyValuesHolder holderY = PropertyValuesHolder.ofFloat("scaleY", 0f,1f);

        ObjectAnimator animation = ObjectAnimator.ofPropertyValuesHolder(view, holderX, holderY);
        animation.setDuration(5000);
        animation.start();

它通过创建PropertyValuesHolder对象,然后将对象给需要修改的对象使用,动画框架将会修改对象的对于属性值。

对比Wrapper的这种方式,PropertyValuesHolder能够轻松的实现多值的同时修改,并且不需要改变目标对象。


(八)Wrapper方式与多对象

之前说的全是一个对象,假设是一组对象呢?

Wrapper立马大显身手,一下将问题解决了:

    static class Wrapper {
        private View[] views;

        public Wrapper(View[] views) {
            this.views = views;
        }

        public void setMagic(float magic) {
            for (View view : views) {
                view.setAlpha(magic);
            }
        }
    }

(九)不指定target的ValueAnimator

ValueAnimator是除了Wrapper的另外一种灵活的实现。
也就是不指定特定的对象,而是在值发生变化的时候,再决定修改哪些对象的哪些具体的值。

那么之前的alpha动画可以改成这样的实现:
        ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f);
        animation.addUpdateListener(new AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float alpha = (Float) (animation.getAnimatedValue());
                view.setAlpha(alpha);
            }
        });
        animation.setDuration(5000);
        animation.start();

(十)AnimatorListener 与 AnimatorUpdateListener

当你希望在动画 [开始],[结束],[取消]或者[重复]的时候做一些事情,使用AnimatorListener。

        animation.addListener(new AnimatorListener() {

            @Override
            public void onAnimationStart(Animator animation) {
            }

            @Override
            public void onAnimationRepeat(Animator animation) {
            }

            @Override
            public void onAnimationEnd(Animator animation) {
            }

            @Override
            public void onAnimationCancel(Animator animation) {
            }
        });

而上一节中提到的AnimatorUpdateListener只有ValueAnimator类才有。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值