ValueAnimator及ObjectAnimator的使用

本文深入探讨了Android中自定义动画的实现方法,包括ValueAnimator和ObjectAnimator的工作原理及使用技巧,同时还介绍了如何利用PropertyValueHolder同时改变多个属性进行动画,并通过关键帧实现复杂动画效果。
public class ChangedCircleView extends View {
    private Round mRound;
    private Paint mPaint;
    private int mLength;
    private int color = Color.RED;

    public ChangedCircleView(Context context) {
        super(context);
        init();
    }

    public ChangedCircleView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public ChangedCircleView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
        mPaint.setColor(color);
        mPaint.setStyle(Paint.Style.FILL);
        mRound = new Round(50);
    }

    /**
     * ObjectAnimator中何时调用getXxx()方法?
     * 1) 当且仅当动画的只有一个过渡值时,系统才会调用对应属性的get函数来得到动画的初始值
     * 2) 如果没有给定getXxx(),系统会给出警告,并默认初始值为0.
     */
    public int getRoundRadius() {
        return mRound.radius;
    }

    //提供set方法,供objectAnimator反射调用
    private void setRoundRadius(int radius) {
        mRound.radius = radius;
        invalidate();
    }

    /**
     * Method setRound() with type class com.bugull.droid.sample.animatior.ChangedCircleView$Round
     * not found on target class class com.bugull.droid.sample.animatior.ChangedCircleView
     *
     * @param round
     */
    private void setRound(Round round) {
        mRound = round;
        invalidate();
    }

    private void setColor(int color) {
//        this.color = color;
        mPaint.setColor(color);
        invalidate();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        int desireWith = getDefaultSize(width, widthMeasureSpec);
        int desireHeight = getDefaultSize(height, heightMeasureSpec);
        mLength = Math.min(desireHeight, desireWith);
        setMeasuredDimension(desireWith, desireWith);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.save();
        canvas.translate(mLength / 2, mLength / 2);
        canvas.drawCircle(0, 0, mRound.radius, mPaint);
        canvas.restore();
    }

    /**
     * 1) ValueAnimator只负责对指定的数字区间进行动画运算
     * 2) 我们需要对运算过程进行监听,然后自己对控件做动画操作
     */
    public void doValueAnimator() {
        ValueAnimator animator = ValueAnimator.ofObject(new RoundEvaluator(), new Round(8), new Round(100));
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                Round r = (Round) animation.getAnimatedValue();
                mRound.radius = r.radius;
                invalidate();
            }
        });

        animator.setDuration(2000);
        animator.setRepeatCount(ValueAnimator.INFINITE);
        animator.setRepeatMode(ValueAnimator.REVERSE);
        animator.setInterpolator(new AccelerateInterpolator());
        animator.start();
    }

    /**
     * ObjectAnimator的实现原理:
     * 1.加速器产生当前进度的百分比,然后再经过Evaluator生成对应百分比所对应的数字值
     * 2.先根据属性值拼装成对应的set函数的名字,,然后通过反射找到对应控件的setXxx()函数,将当前数字值做为setXxx()参数将其传入。
     * 3.其中参数类型的确定:靠估值器(Evaluator)
     * 4.拼接成setXxx()后,反射调用执行了什么:1)重新设置当前控件的参数,2)调用Invalidate()强制重绘;
     * 5.setXxx()调用频率:动画每隔十几毫秒会刷新一次,set函数也会每隔十几毫秒会被调用一次。
     */
    public void doObjectAnimator() {
        ObjectAnimator animator = ObjectAnimator.ofInt(this, "roundRadius", 8, 100);
        animator.setDuration(1000);
        animator.setRepeatCount(ValueAnimator.INFINITE);
        animator.setRepeatMode(ValueAnimator.REVERSE);
        animator.setInterpolator(new AccelerateInterpolator());
        animator.start();
    }

    /**
     * 使用PropertyValueHolder同时改变view多个属性进行动画:
     */
    public void doHolderAnimator() {

        PropertyValuesHolder rHolder = PropertyValuesHolder.ofInt("roundRadius", 50, 100);
        PropertyValuesHolder cHolder = PropertyValuesHolder.ofInt("color", 0xff00ff00, 0xff0000ff);
        ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(this, rHolder, cHolder);

        animator.setDuration(3000);
        animator.setRepeatCount(ValueAnimator.INFINITE);
        animator.setRepeatMode(ValueAnimator.REVERSE);
        animator.setInterpolator(new AccelerateInterpolator());
        animator.start();
    }

    public void doObjectHolderAnimator() {

        PropertyValuesHolder oHolder = PropertyValuesHolder.ofObject("Round", new RoundEvaluator(), new Round(8), new Round(100));
        ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(this, oHolder);

        animator.setDuration(3000);
        animator.setRepeatCount(ValueAnimator.INFINITE);
        animator.setRepeatMode(ValueAnimator.REVERSE);
        animator.setInterpolator(new AccelerateInterpolator());
        animator.start();
    }

    /**
     * 使用关键帧,实现多个动画同时播放
     * 对于Keyframe而言,fraction和value这两个参数是必须有的,所以无论用哪种方式实例化Keyframe都必须保证这两个值必须被初始化。
     */
    public void doKeyFrameAnimator() {
        Keyframe k1 = Keyframe.ofInt(0, 10);
        Keyframe k2 = Keyframe.ofInt(0.2F, 50);
        Keyframe k3 = Keyframe.ofInt(0.5F, 80);
        Keyframe k4 = Keyframe.ofInt(1.0F, 100);

        Keyframe f1 = Keyframe.ofInt(0, 0xff0000ff);
        Keyframe f2 = Keyframe.ofInt(0.2f, 0xff000fff);
        Keyframe f3 = Keyframe.ofInt(0.4f, 0xff00ffff);
        Keyframe f4 = Keyframe.ofInt(1.0f, 0xfffff0ff);

        Keyframe o1=Keyframe.ofObject(0, new Round(10));
        Keyframe o2=Keyframe.ofObject(0.3f, new Round(50));
        Keyframe o3=Keyframe.ofObject(0.6f, new Round(70));
        Keyframe o4=Keyframe.ofObject(1.0f,new Round(100));

        PropertyValuesHolder rHolder = PropertyValuesHolder.ofKeyframe("roundRadius", k1, k2, k3, k4);
        PropertyValuesHolder cHolder = PropertyValuesHolder.ofKeyframe("color", f1, f2, f3, f4);
        PropertyValuesHolder oHolder=PropertyValuesHolder.ofKeyframe("round",o1,o2,o3,o4);
        /*使用ofObject必须要设置自定义的Evaluator*/
        oHolder.setEvaluator(new RoundEvaluator());

        ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(this, rHolder, cHolder);

        animator.setDuration(3000);
        animator.setRepeatCount(ValueAnimator.INFINITE);
        animator.setRepeatMode(ValueAnimator.REVERSE);
        animator.setInterpolator(new AccelerateInterpolator());
        animator.start();

    }

    public class Round {
        public int radius;

        public Round(int radius) {
            this.radius = radius;
        }
    }

    private class RoundEvaluator implements TypeEvaluator<Round> {

        @Override
        public Round evaluate(float fraction, Round startValue, Round endValue) {
            int startRadius = startValue.radius;
            int endRadius = endValue.radius;
            return new Round((int) (startRadius + fraction * (endRadius - startRadius)));
        }
    }

}
`ValueAnimator` 和 `ObjectAnimator` 都是 Android 属性动画系统中的核心类,它们都继承自 `Animator` 类,但使用方式和适用场景有所不同。 --- ## ✅ 一、`ValueAnimator` 的使用案例 ### 特点: - 只负责计算动画过程中的数值(如从 0 到 1)。 - 不直接操作对象的属性。 - 需要手动监听数值变化,并更新目标对象。 ### 使用场景: - 自定义动画逻辑。 - 无 setter 方法的对象属性动画- 绘图动画、进度条更新等。 ### 示例代码(实现一个自定义的透明度动画): ```java ValueAnimator animator = ValueAnimator.ofFloat(1.0f, 0.0f); animator.setDuration(1000); animator.addUpdateListener(animation -> { float alpha = (float) animation.getAnimatedValue(); myView.setAlpha(alpha); // 手动设置透明度 }); animator.start(); ``` --- ## ✅ 二、`ObjectAnimator` 的使用案例 ### 特点: - 继承自 `ValueAnimator`。 - 可以直接操作对象的属性(前提是该属性有对应的 setter 方法)。 - 更加简洁,适合大多数 UI 动画。 ### 使用场景: - 操作 View 的 `alpha`、`translationX`、`rotation` 等标准属性。 - 快速实现属性动画,无需手动监听和设置值。 ### 示例代码(实现透明度动画): ```java ObjectAnimator animator = ObjectAnimator.ofFloat(myView, "alpha", 1.0f, 0.0f); animator.setDuration(1000); animator.start(); ``` --- ## ✅ 三、区别对比总结 | 对比项 | `ValueAnimator` | `ObjectAnimator` | |--------|------------------|------------------| | 是否直接操作属性 | 否 | 是 | | 是否需要 setter 方法 | 不需要 | 需要 | | 使用复杂度 | 较高(需手动监听) | 简单(自动操作属性) | | 适用场景 | 自定义动画、无 setter 属性 | 标准 View 属性动画 | | 示例 | 自定义进度动画、路径动画 | View 的透明度、缩放、位移等 | --- ## ✅ 四、选择建议 - 如果你想对某个自定义对象或没有 setter 方法的属性做动画使用 `ValueAnimator`。 - 如果你要对标准 View 的属性做动画,优先使用 `ObjectAnimator`,更简洁高效。 ---
### ValueAnimator介绍 ValueAnimatorAndroid中属性动画框架的核心类,用于实现值的动画变化。它并不直接作用于某个对象,而是通过计算值的变化,开发者可以监听这些值的变化并应用到具体的对象上。ValueAnimator提供了一系列方法来定义动画的持续时间、插值器等,支持多种类型的值,如int、float等。 ### ValueAnimator使用方法 以下是一个简单的ValueAnimator示例,实现从0到100的数值变化: ```java ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 100); valueAnimator.setDuration(1000); // 设置动画时长为1秒 valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { int animatedValue = (int) animation.getAnimatedValue(); // 可以将animatedValue应用到具体的对象上 Log.d("ValueAnimator", "Animated Value: " + animatedValue); } }); valueAnimator.start(); ``` ### ObjectAnimator介绍 ObjectAnimatorValueAnimator的子类,它可以直接对对象的属性进行动画操作。通过指定对象和属性名,ObjectAnimator会自动更新对象的属性值,无需开发者手动监听值的变化。 ### ObjectAnimator使用方法 以下是一个简单的ObjectAnimator示例,实现View的透明度从1到0的变化: ```java ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view, "alpha", 1f, 0f); objectAnimator.setDuration(1000); // 设置动画时长为1秒 objectAnimator.start(); ``` ### 两者区别 - **作用对象**:ValueAnimator不直接作用于对象,只是计算值的变化;而ObjectAnimator可以直接对对象的属性进行动画操作[^1]。 - **使用复杂度**:ValueAnimator需要开发者手动监听值的变化并应用到对象上,使用相对复杂;ObjectAnimator使用更简单,只需指定对象和属性名即可。 - **应用场景**:ValueAnimator适用于需要自定义动画逻辑的场景;ObjectAnimator适用于对对象属性进行简单动画操作的场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值