• 逐帧动画:在时间轴的每帧上逐帧绘制不同的内容,使其连续播放而成动画。
  • 补间动画:对View进行一系列的动画操作,包括淡入淡出、缩放、平移、旋转四种。
  • 属性动画(property animation):是一种不断地对值进行操作的机制,并将值赋值到指定对象的指定属性上,可以是任意对象的任意属性。

为什么要引入属性动画(Android 3.0版本)?

补间动画只能作用在View上;且只能实现淡入淡出、缩放、平移、旋转这四种动画操作;它只是改变了View的显示效果而已,却没有改变View的属性,也就是说移动button后对Button的点击事件会失效,因为属性坐标没有相应的更新。

属性动画主要有四个点:ValueAnimator、ObjectAnimator、Interpolator、TypeEvaluator

ValueAnimator

它的内部使用一种时间循环的机制来计算值与值之间的动画过渡,我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果。除此之外,ValueAnimator还负责管理动画的播放次数、播放模式、以及对动画设置监听器等。需要手动对View进行操作。

ValueAnimator类中有3个重要方法:

  • ValueAnimator.ofInt(int values) //采用默认的整型估值器(IntEvaluator)
  • ValueAnimator.ofFloat(float values) //采用默认的浮点型估值器 (FloatEvaluator)
  • ValueAnimator.ofObject(int values)//将初始值以对象的形式过渡到结束值,需要自定义估值器,将多个值 封装到一个对象里进行统筹操作。

// 设置动画延迟播放时间
        valueAnimator.setStartDelay(500);
        // 设置动画重复播放次数 = 重放次数+1
        // 动画播放次数 = infinite时,动画无限重复
        valueAnimator.setRepeatCount(0);
        // 设置重复播放动画模式
        // ValueAnimator.RESTART(默认):正序重放
        // ValueAnimator.REVERSE:倒序回放
        valueAnimator.setRepeatMode(ValueAnimator.RESTART);
复制代码



示例: ValueAnimator.addUpdateListener监听这个动画的改变,监听到valueAnimator的变化,则手动对对象进行操作

//Point只是一个简单的点坐标
 data class Point(var x: Float, var y: Float)
    /**
     * 移动 ofObject
     * PointEvaluator实现了TypeEvaluator,具体实现见下文TypeEvaluator
     */
    private void changeIcon1() {
        Point startPoint = new Point(icon.getX(), icon.getY());// 初始点为圆心
        Point endPoint = new Point(0, 0); // 结束点为(0,0)
        ValueAnimator valueAnimator = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);
        valueAnimator.setDuration(2000);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                Point currentPoint = (Point) animation.getAnimatedValue();
                Log.e("zhen", "currentValue: " + currentPoint.toString());
                icon.setX(currentPoint.getX());
                icon.setY(currentPoint.getY());
                icon.requestLayout();
            }
        });
        valueAnimator.start();
    }

    /**
     * 缩小 ofInt
     */
    private void changeIcon() {
        ValueAnimator valueAnimator = ValueAnimator.ofInt(icon.getLayoutParams().width,
                DensityUtil.dp2px(this, 36));
        valueAnimator.setDuration(2000);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int currentValue = (int) animation.getAnimatedValue();
                Log.e("zhen", "currentValue: " + currentValue);
                icon.getLayoutParams().width = currentValue;
                icon.getLayoutParams().height = currentValue;
                icon.requestLayout();
            }
        });
        valueAnimator.start();
    }
复制代码

ObjectAnimator:

ObjectAnimator继承自ValueAnimator,即具备ValueAnimator的所有属性

通过不断控制值的变化,再不断自动赋给对象的属性,从而实现动画效果。

ObjectAnimator.ofFloat(Object object, String property, float ....values)指定了要操作的对象object;根据property属性名去寻找该对象对应属性名的 set() & get()方法,从而进行对象属性值的赋值;values指定了赋值的初始值和结束值

如果需要采用ObjectAnimator 类实现动画效果,那么需要操作的对象就必须有该属性的set() & get();

除了rotation、rotationX、rotationY、alpha、scale、scaleX、scaleY、translationX、translationY,还可以自定义属性

//垂直方向的大小缩小为0.5倍
 private void changeNameWithScaleY() {
        ObjectAnimator animator = ObjectAnimator.ofFloat(tvName,"scaleY", 1, 0.5F);
        animator.setDuration(2000);
        animator.start();
    }

    //水平方向的大小缩小为0.5倍
    private void changeNameWithScaleX() {
        ObjectAnimator animator = ObjectAnimator.ofFloat(tvName,"scaleX", 1, 0.5F);
        animator.setDuration(2000);
        animator.start();
    }

    //Y方向移动,当前控件所在位置为原点,遵循android坐标系
    private void changeNameWithTransitionY() {
        ObjectAnimator animator = ObjectAnimator.ofFloat(tvName,"translationY", tvName.getY(), 0);
        animator.setDuration(2000);
        animator.start();
    }
    
    //X方向移动,当前控件所在位置为原点,遵循android坐标系
    private void changeNameWithTransitionX() {
        ObjectAnimator animator = ObjectAnimator.ofFloat(tvName,"translationX", 100, 300);
        animator.setDuration(2000);
        animator.start();
    }

    //旋转
    private void changeNameWithRotate() {
        ObjectAnimator animator = ObjectAnimator.ofFloat(tvName,"rotation", 0, 180, 0);
        animator.setDuration(2000);
        animator.start();
    }

    //改变透明度,从不透明1变为透明0,又变为不透明1
    private void changeNameWithAlpha() {
        ObjectAnimator animator = ObjectAnimator.ofFloat(tvName,"alpha", 1f, 0.5f, 1);
        animator.setDuration(2000);
        animator.start();
    }
复制代码

插值器(Interpolator):

决定值的变化模式(匀速、加速、弹跳效果)

除了系统自带的interpolator,还可自定义interpolator

  • AccelerateDecelerateInterpolator: 在动画开始与结束的地方速率改变比较慢,在中间的时候加速
  • AccelerateInterpolator: 在动画开始的地方速率改变比较慢,然后开始加速
  • AnticipateInterpolator: 开始的时候向后然后向前甩
  • AnticipateOvershootInterpolator: 开始的时候向后然后向前甩一定值后返回最后的值
  • BounceInterpolator: 动画结束的时候弹起
  • CycleInterpolator: 动画循环播放特定的次数,速率改变沿着正弦曲线
  • DecelerateInterpolator: 在动画开始的地方快然后慢
  • LinearInterpolator: 以常量速率改变
  • OvershootInterpolator: 向前甩一定值后再回到原来位置
//在animator之前设置interpolator 为加速运动模型
valueAnimator.setInterpolator(new AccelerateInterpolator());
复制代码

估值器(TypeEvaluator)

设置动画如何从初始值过渡到结束值的逻辑

相当于是你告诉了系统你的起点、终点和消耗时间,系统自动的为你规划好了一条路线。

系统内置的Evaluator: IntEvaluator、FloatEvaluator,都是实现的TypeEvaluator。

public class IntEvaluator implements TypeEvaluator<Integer> {

    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
        int startInt = startValue;
        return (int)(startInt + fraction * (endValue - startInt));
    }
}
复制代码
public class FloatEvaluator implements TypeEvaluator<Number> {

    public Float evaluate(float fraction, Number startValue, Number endValue) {
        float startFloat = startValue.floatValue();
        return startFloat + fraction * (endValue.floatValue() - startFloat);
    }
}
复制代码

自定义TypeEvaluator

fraction表示动画的完成度,第二三个参数分别表示动画的初始值和结束值

这里实现的是上面的小圆点Point (将x坐标、y坐标封装为一个整体,交给我们去处理)

//PointEvaluator实现了TypeEvaluator
 public class PointEvaluator implements TypeEvaluator {
    @Override
    public Object evaluate(float fraction, Object startValue, Object endValue) {
        // 将动画初始值startValue 和 动画结束值endValue 强制类型转换成Point对象
        Point startPoint = (Point) startValue;
        Point endPoint = (Point) endValue;

        // 根据fraction来计算当前动画的x和y的值
        float x = startPoint.getX() + fraction * (endPoint.getX() - startPoint.getX());
        float y = startPoint.getY() + fraction * (endPoint.getY() - startPoint.getY());

        // 将计算后的坐标封装到一个新的Point对象中并返回
        Point point = new Point(x, y);
        return point;
    }
}
复制代码

AnimationSet组合动画

AnimatorSet.play(Animator anim)   :播放当前动画
AnimatorSet.after(long delay)   :将现有动画延迟x毫秒后执行
AnimatorSet.with(Animator anim)   :将现有动画和传入的动画同时执行
AnimatorSet.after(Animator anim)   :将现有动画插入到传入的动画之后执行
AnimatorSet.before(Animator anim) :  将现有动画插入到传入的动画之前执行
复制代码

让name随着icon一起移动到左上角,changeName用的是animatorSet

translation默认所操作的控件为坐标原点,其余坐标操作遵循android坐标系

private void changeName() {
        ObjectAnimator animatorX = ObjectAnimator.ofFloat(tvName,"translationX", 0, - tvName.getX() + DensityUtil.dp2px(this, 58));

        ObjectAnimator animatorY = ObjectAnimator.ofFloat(tvName,"translationY", 0, - tvName.getY());

        ObjectAnimator animatorScale = ObjectAnimator.ofFloat(tvName,"scale", 1, 0.5F);
        
        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.play(animatorX).with(animatorY).with(animatorScale);
        animatorSet.setDuration(2000);
        animatorSet.start();
    }
复制代码

animator的监听

AnimatorListenerAdapter实现了Animator.AnimatorListener和Animator.AnimatorPauseListener,可实现其中1-n个方法

valueAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
                //在动画开始的时候调用
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                //在动画结束的时候调用
            }

            @Override
            public void onAnimationCancel(Animator animation) {
                //在动画被取消的时候调用
            }

            @Override
            public void onAnimationRepeat(Animator animation) {
                //在动画重复执行的时候调用
            }
        });

        valueAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationStart(Animator animation) {
                super.onAnimationStart(animation);
            }
        });
     
     //AnimatorListenerAdapter实现了Animator.AnimatorListener和Animator.AnimatorPauseListener,可实现其中1-n个方法
        public abstract class AnimatorListenerAdapter implements Animator.AnimatorListener,
        Animator.AnimatorPauseListener
复制代码