Android 属性动画

属性动画

概述

  • Android3.0之前的动画框架存在一些缺陷,动画改变的只是显示,并不能响应事件。
  • 在Android3.0之后,谷歌推出全新的动画框架,实现机制是通过对目标对象进行赋值并修改其属性来实现的 。

ObjectAnimator

ObjectAnimator可以直接对任意对象的任意属性进行动画操作。

基本属性

public class Constant {
    public static final String TRANSLATION_X = "translationX";
    public static final String TRANSLATION_Y = "translationY";
    public static final String SCALE_X = "scaleX";
    public static final String SCALE_Y = "scaleY";
    public static final String ROTATION = "rotation";
    public static final String ALPHA = "alpha";
}

旋转动画

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);
}

Interpolator 插值器

作用:设置属性值从初始值过渡到结束值的变化规律,通过操作动画之下的进度(0%-100%)计算属性值

Android系统内置9种插值器

  • 匀速:资源ID@android:anim/linear_interpolator Java类LinearInterpolator
  • 减速:资源ID@android:anim/decelerate_interpolator Java类DecelerateInterpolator
  • 加速:资源ID@android:anim/accelerate_interpolator Java类AccelerateInterpolator
  • 快速完成动画,超出再回到结束样式:资源ID@android:anim/overshoot_interpolator Java类OvershootInterpolator
  • 先加速再减速:资源ID@android:anim/accelerate_decelerate_interpolator Java类AccelerateDecelerateInterpolator
  • 先退后再加速前进:资源ID@android:anim/anticipate_interpolator Java类AnticipateInterpolator
  • 先退后再加速前进,超出终点后再回终点:资源ID@android:anim/anticipate_overshoot_interpolator Java类AnticipateOvershootInterpolator
  • 最后阶段弹球效果:资源ID@android:anim/bounce_interpolator Java类BounceInterpolator
  • 周期运动:资源ID@android:anim/cycle_interpolator Java类CycleInterpolator

说明:在XML文件中使用资源ID,在代码中使用差值器对象

使用系统插值器

在这里插入图片描述

ArrayList<Interpolator> interpolators = new ArrayList<Interpolator>() {
    {
        add(new LinearInterpolator());//匀速
        add(new DecelerateInterpolator());//减速
        add(new AccelerateInterpolator());//加速
        add(new OvershootInterpolator());//快速完成动画,超出再回到结束样式
        add(new AccelerateDecelerateInterpolator());//先加速再减速
        add(new AnticipateInterpolator());//先退后再加速前进
        add(new AnticipateOvershootInterpolator());//先退后再加速前进,超出终点后再回终点
        add(new BounceInterpolator());//最后阶段回弹效果
        add(new CycleInterpolator(3));//周期运动
    }
};

for (int i = 0; i < textViews.size(); i++) {
    TextView textView = textViews.get(i);
    ObjectAnimator animator = ObjectAnimator.ofFloat(textView, Constant.TRANSLATION_X, 0, 1000F);
    animator.setDuration(5000L);
    animator.setInterpolator(interpolators.get(i));
    animator.start();
}

自定义差值器

public class MyInterpolator implements Interpolator {
    @Override
    public float getInterpolation(float input) {
        Log.e("TAG", "input: " + input);
        input = input - 0.5f;
        return (float) Math.sin(60 * input) + 0.5f;
    }
}

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;
        }
    }
}

代码下载

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android属性动画是一种用于在Android应用程序中创建动画效果的框架。它允许您对任意对象的属性进行动画处理,而不仅仅是视图对象。使用属性动画,您可以平滑地改变对象的属性,如位置、大小、颜色等,从而创建流畅的动画效果。 属性动画的基本概念是通过改变对象的属性值来实现动画效果,而不是通过改变视图的位置或绘制来实现。这使得属性动画比传统的补间动画更加灵活和强大。 要使用属性动画,您需要创建一个Animator对象,并指定要动画化的目标对象和属性。然后,您可以定义动画的持续时间、插值器和监听器等属性。最后,启动动画并观察目标对象的属性值的平滑变化。 以下是一个简单的示例,演示如何使用属性动画来平滑地改变视图对象的透明度: ```java // 创建一个属性动画对象,指定要改变的属性为视图对象的透明度 ObjectAnimator animator = ObjectAnimator.ofFloat(view, "alpha",***.setDuration(1000); // 设置插值器,控制动画的变化速率 animator.setInterpolator(new AccelerateDecelerateInterpolator()); // 启动动画 animator.start(); ``` 在上面的示例中,我们创建了一个ObjectAnimator对象,指定要改变的属性为视图对象的透明度。然后,我们设置了动*** 除了ObjectAnimatorAndroid还提供了一些其他类型的属性动画,如ValueAnimator和AnimatorSet。这些类可用于更复杂的动画效果,如同时播放多个动画或在动画中修改多个属性。 希望这个简介能帮助您理解Android属性动画的基本概念和用法。如果您有更多问题,请随时提问!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值