Android属性动画解析和实例

  • 逐帧动画(Frame Animation):在时间轴的每帧上逐帧绘制不同的内容,使其连续播放而成动画。

  • 补间动画(Tweened Animation):对View进行一系列的动画操作,包括淡入淡出、缩放、平移、旋转四种。

  • 属性动画(Property Animation):是一种不断地对值进行操作的机制,并将值赋值到指定对象的指定属性上,可以是任意对象的任意属性。

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

补间动画的特性

  • 只能作用在View上

  • 只能实现透明度alpha、缩放scale、平移translate、旋转rotate这四种动画操作

  • 只是改变了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.ofArgb(int… values) //采用默认的颜色估值器ArgbEvaluator
  • ValueAnimator.ofObject(TypeEvaluator evaluator, Object… values)//将初始值以对象的形式过渡到结束值,需要自定义估值器,将多个值 封装到一个对象里进行统筹操作。
        // 设置动画延迟播放时间
        valueAnimator.setStartDelay(500);
        // 设置动画重复播放次数 = 重放次数+1
        // 动画播放次数 = infinite时,动画无限重复
        valueAnimator.setRepeatCount(0);
        // 设置重复播放动画模式
        // ValueAnimator.RESTART(默认):正序重放
        // ValueAnimator.REVERSE:倒序回放
        valueAnimator.setRepeatMode(ValueAnimator.RESTART);

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

//取消监听
valueAnimator.removeAllUpdateListeners() 
valueAnimator.removeUpdateListener(AnimatorUpdateListener listener)
//取消动画
valueAnimator.cancel();
//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

参考
Android属性动画完全解析(上),初识属性动画的基本用法
Android属性动画完全解析(中),ValueAnimator和ObjectAnimator的高级用法
Android属性动画完全解析(下),Interpolator和ViewPropertyAnimator的用法

Android 属性动画:这是一篇很详细的 属性动画 总结&攻略
Android 动画:你真的会使用插值器与估值器吗?(含详细实例教学)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值