美文网首页
属性动画一 基本使用

属性动画一 基本使用

作者: scarerow | 来源:发表于2017-06-11 16:39 被阅读0次

    一 为什么引入属性动画

    1. 补间动画只有四种(移动、缩放、旋转和淡入淡出)

    补间动画还有一个缺陷,就是它只能够实现移动、缩放、旋转和淡入淡出这四种动画操作,那如果我们希望可以对View的背景色进行动态地改变呢?很遗憾,我们只能靠自己去实现了。说白了,之前的补间动画机制就是使用硬编码的方式来完成的,功能限定死就是这些,基本上没有任何扩展性可言。

    1. 补间动画只能作用于view,不能作用于canvas画出的图形

    2. 补间动画有个致命的缺陷:它只是改变了View的显示效果而已,而不会真正去改变View的属性

    比如说,现在屏幕的左上角有一个按钮,然后我们通过补间动画将它移动到了屏幕的右下角,现在你可以去尝试点击一下这个按钮,点击事件是绝对不会触发的,因为实际上这个按钮还是停留在屏幕的左上角,只不过补间动画将这个按钮绘制到了屏幕的右下角而已。

    二 属性动画基本使用

    新引入的属性动画机制已经不再是针对于View来设计的了,也不限定于只能实现移动、缩放、旋转和淡入淡出这几种动画操作,同时也不再只是一种视觉上的动画效果了。它实际上是一种不断地对值进行操作的机制,并将值赋值到指定对象的指定属性上,可以是任意对象的任意属性。所以我们仍然可以将一个View进行移动或者缩放,但同时也可以对自定义View中的Point对象进行动画操作了。我们只需要告诉系统动画的运行时长,需要执行哪种类型的动画,以及动画的初始值和结束值,剩下的工作就可以全部交给系统去完成了。

    1 ValueAnimator

    ValueAnimator是整个属性动画机制当中最核心的一个类,前面我们已经提到了,属性动画的运行机制是通过不断地对值进行操作来实现的,而初始值和结束值之间的动画过渡就是由ValueAnimator这个类来负责计算的。它的内部使用一种时间循环的机制来计算值与值之间的动画过渡,我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果。除此之外,ValueAnimator还负责管理动画的播放次数、播放模式、以及对动画设置监听器等,确实是一个非常重要的类。

    基本使用

    ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);  
    anim.setDuration(300);  
    anim.start();
    

    监听value的改变

    ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);  
    anim.setDuration(300);  
    anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {  
        @Override  
        public void onAnimationUpdate(ValueAnimator animation) {  
            float value = (float) animation.getAnimatedValue();//得到0f~100f当中的这个时间点对应的值
            float percent = (float) animation.getAnimatedFraction();// 动画执行的百分比 0~1
        }  
    });  
    anim.start();
    

    常用方法

    可以使用的偏移量
    ValueAnimator.ofFloat(1f);//浮点数
    ValueAnimator.ofArgb(Color.BLACK);//颜色偏移
    ValueAnimator.ofInt(1);//整形
    ValueAnimator.ofObject();//对象
    ValueAnimator.ofPropertyValuesHolder();
    
    setStartDelay()//方法来设置动画延迟播放的时间,
    setRepeatCount()//设置动画循环播放的次数
    setRepeatMode()//循环播放的模式,循环模式包括RESTART和REVERSE两种,分别表示重新播放和倒序播放的意思。
    animator.setDuration(5000);  // 动画播放时长
    

    2 ObjectAnimator

    相比于ValueAnimator,ObjectAnimator可能才是我们最常接触到的类,因为ValueAnimator只不过是对值进行了一个平滑的动画过渡,但我们实际使用到这种功能的场景好像并不多。而ObjectAnimator则就不同了,它是可以直接对任意对象的任意属性进行动画操作的,比如说View的alpha属性。

    一个TextView在5秒中内从常规变换成全透明,再从全透明变换成常规,就可以这样写:

    ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);  
    animator.setDuration(5000);  
    animator.start();
    

    大概原理

    //1.-------------属性动画基础--------------------
    iv.setTranslationX(100);
    iv.setScaleX(scaleX);
    iv.setAlpha(alpha);
    iv.setRotation(rotation)
    iv.setBackgroundColor(color);
            
    //只要view里面有setXXX()方法就可以通过反射达到变化的目的
    ObjectAnimator oa = ObjectAnimator.ofFloat(iv, "translationX", 0f,200f);
    //ObjectAnimator oa = ObjectAnimator.ofFloat(iv, "backgroundColor", Color.RED,Color.BLUE);
    oa.setDuration(500);
    oa.start();
    

    监听值变化用ValueAnimator

            //方法 2)---------------ValueAnimator---如果只需要监听值变化就用ValueAnimator---------------
            ValueAnimator animator = ValueAnimator.ofFloat(0f, 200f);
            animator.setDuration(200);
            animator.addUpdateListener(new AnimatorUpdateListener() {
                
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    float value = (float) animation.getAnimatedValue();//得到0f~100f当中的这个时间点对应的值
                    iv.setScaleX(0.5f+value/200);
                    iv.setScaleY(0.5f+value/200);
                }
            });
            animator.start();
    

    PropertyValuesHolder

    //  ObjectAnimator内部使用了PropertyValuesHolder,所以这里传入PropertyValuesHolder也ok
            PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("alpha", 1f, 0.5f);
            PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("scaleX", 1f, 0.5f);
            PropertyValuesHolder holder3 = PropertyValuesHolder.ofFloat("scaleY", 1f, 0.5f);
            ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(iv, holder1, holder2, holder3);
            animator.setDuration(200);
            animator.start();
    

    3 动画组合

    函数介绍

            animator.setRepeatCount(2);//重复两次
            animator.setRepeatCount(ValueAnimator.INFINITE);//无限重复
            animator.setRepeatMode(ValueAnimator.RESTART);// 重新开始
            animator.setRepeatMode(ValueAnimator.REVERSE);
            animatorSet.play(animator3).with(animator2).after(animator1);//animator1在前面
            animatorSet.play(animator3).with(animator2).before(animator1);//animator1在后面
            animatorSet.playTogether(animator1, animator2, animator3);// 一起执行
            animatorSet.playSequentially(animator1, animator2, animator3);// 一个个按顺序来执行
    

    例子:

    
    
     //-------------动画集合-----------------
            ImageView iv = new ImageView(this);
            ObjectAnimator animator1 = ObjectAnimator.ofFloat(iv, "translationX", 0f, 100f);
            animator1.setRepeatCount(3);
            ObjectAnimator animator2 = ObjectAnimator.ofFloat(iv, "alpha", 0f, 1f);
            animator2.setStartDelay(startDelay);//设置延迟执行
            ObjectAnimator animator3 = ObjectAnimator.ofFloat(iv, "scaleX", 0f, 2f);
            AnimatorSet animatorSet = new AnimatorSet();
            animatorSet.setDuration(500);
            animatorSet.play(animator3).with(animator2).after(animator1);//animator1在前面
            animatorSet.play(animator3).with(animator2).before(animator1);//animator1在后面
            animatorSet.playTogether(animator1, animator2, animator3);
            animatorSet.playSequentially(animator1, animator2, animator3);// 一个个按顺序来执行
            animatorSet.start();
    

    4 动画监听

    常用监听函数

    1. 监听值变化
            final ObjectAnimator animator = ObjectAnimator.ofFloat(iv, "hehe", 0f, 100f);
            animator.setDuration(300);
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    // 监听动画回调
                    animation.getAnimatedFraction();//动画执行的百分比 0~1 //API 12+
                    float value = (float) animation.getAnimatedValue();//得到0f~100f当中的这个时间点对应的值
                    iv.setScaleX(0.5f + value / 200);
                    iv.setScaleY(0.5f + value / 200);
                    iv.setTranslationX(value);
                }
            });
            animator.start();
    
    1. 监听动画执行
     animator.addListener(new Animator.AnimatorListener() {
    
                @Override
                public void onAnimationStart(Animator animation) {
                }
    
                @Override
                public void onAnimationRepeat(Animator animation) {
                }
    
                @Override
                public void onAnimationEnd(Animator animation) {
                    animator.setRepeatCount(ValueAnimator.RESTART);
                }
    
                @Override
                public void onAnimationCancel(Animator animation) {
                }
            });
    
    1. 监听动画执行可选部分监听
    // 监听特定的函数:AnimatorListenerAdapter是一个抽象函数,实现了Animator.AnimatorListener接口
            animator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    // TODO Auto-generated method stub
                    super.onAnimationEnd(animation);
                }
            });
    

    5 插值器

    Interpolator这个东西很难进行翻译,直译过来的话是补间器的意思,它的主要作用是可以控制动画的变化速率,比如去实现一种非线性运动的动画效果。那么什么叫做非线性运动的动画效果呢?就是说动画改变的速率不是一成不变的,像加速运动以及减速运动都属于非线性运动。

    决定某个时间执行哪段曲线

    //6.---------插值器(加速器)Interpolater-----------
            ObjectAnimator oa = ObjectAnimator.ofFloat(iv, "translationY", 0f, 1000f);
            oa.setDuration(800);
            //oa.setInterpolator(new AccelerateInterpolator(1));// 加速
            //oa.setInterpolator(new AccelerateDecelerateInterpolator());// 先加速在减速
            oa.setInterpolator(new BounceInterpolator()); // 下落弹起
            //oa.setInterpolator(new AnticipateInterpolator());// 先上再下
            //oa.setInterpolator(new CycleInterpolator(5));
            oa.start();
    
    小球落地插值器效果 几种差值器说明.png

    几种差值器的曲线图

    先加速后减速效果

    AccelerateDecelerateInterpolator 加速减速插值器
    public class AccelerateDecelerateInterpolator extends BaseInterpolator
            implements NativeInterpolatorFactory {
        public AccelerateDecelerateInterpolator() {
        }
        public float getInterpolation(float input) {
            return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
        }
    }
    

    加速效果

    AccelerateInterpolator 加速插值器
    public class AccelerateInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
        private final float mFactor;
        private final double mDoubleFactor;
    
        public AccelerateInterpolator() {
            mFactor = 1.0f;
            mDoubleFactor = 2.0;
        }
    
        public AccelerateInterpolator(float factor) {
            mFactor = factor;
            mDoubleFactor = 2 * mFactor;
        }
    
        public float getInterpolation(float input) {
            if (mFactor == 1.0f) {
                return input * input;
            } else {
                return (float)Math.pow(input, mDoubleFactor);
            }
        }
    
    

    先回弹,再加速

    AnticipateInterpolator 回荡秋千插值器

    先回弹,再加速,减速,再回弹

    AnticipateOvershootInterpolator

    小球落地弹起效果

    BounceInterpolator 弹跳插值器

    正弦波

    CycleInterpolator 正弦周期变化插值器

    减速

    DecelerateInterpolator 减速插值器

    Android基于Facebook Rebound的动画效果框架Backboard demo (非常炫酷)

    6 xml中使用属性动画

    • (1) XML文件位置:res/animator/filename.xml
    • (2) 文件编译后的类型:ValueAnimator, ObjectAnimator, AnimatorSet。
    <set
    // 执行顺序 同时 | 顺序执行
      android:ordering=["together" | "sequentially"]>
    
        <objectAnimator
          // 属性名,alpha translateX scale 
            android:propertyName="string"
            android:duration="int"
            android:valueFrom="float | int | color"
            android:valueTo="float | int | color"
            android:startOffset="int"
            android:repeatCount="int"
            // 差值器:注意位置
            android:interpolator="@android:anim/decelerate_interpolator">
            // 模式 重复,反转重复
            android:repeatMode=["repeat" | "reverse"]
            // 值类型 ofFlaot  ofInt
            android:valueType=["intType" | "floatType"]/>
    
        <animator
            android:duration="int"
            android:valueFrom="float | int | color"
            android:valueTo="float | int | color"
            android:startOffset="int"
            android:repeatCount="int"
            android:repeatMode=["repeat" | "reverse"]
            android:valueType=["intType" | "floatType"]/>
    
        <set>
            ...
        </set>
    </set>
    
    • (3) 引用资源的方式:
    // AnimatorSet
    AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
         R.anim.property_animator);
    set.setTarget(myObject);
    set.start();
    // animator 
    Animator animator = AnimatorInflater.loadAnimator(context, R.animator.anim_file);  
    animator.setTarget(view);  
    animator.start();  
    

    7 TypeEvaluator 估值器

    那么TypeEvaluator的作用到底是什么呢?简单来说,就是告诉动画系统如何从初始值过度到结束值。
    如果是移动,Evaluator能改变移动的轨迹

    Evaluator和Interpolator的区别
    Evaluator(估值器)作用:决定startValue到endValue的轨迹曲线
    Interpolator(差值器)作用:决定某一时间执行哪段曲线,决定每一曲线段的运动速率,重复某部分曲线段效果(小球弹起)

    我们来看一下FloatEvaluator的代码实现:

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

    FloatEvaluator 实现了TypeEvaluator 的evaluate方法, fraction表示执行的百分比, startValue动画开始值, endValue动画结束值,

        //------------------案例:实现自由落体抛物线效果-----------------
        /**
         * x: 匀速
         * y: 加速度 y=vt=1/2*g*t*t
         * 估值器---控制坐标PointF(x,y)
         */
            ValueAnimator valueAnimator = new ValueAnimator();
    //      valueAnimator.setInterpolator(value)
            valueAnimator.setDuration(2000);
            valueAnimator.setObjectValues(new PointF(0, 0));
    //      valueAnimator.setObjectValues(new PointF(0, 0),new PointF(10, 10));
            final PointF pointF = new PointF();
            //颜色估值器
    //      setBackgroundColor((Integer) sArgbEvaluator.evaluate(ratio, mDiscrollveFromBgColor, mDiscrollveToBgColor));
            valueAnimator.setEvaluator(new TypeEvaluator<PointF>() {
    
                @Override
                public PointF evaluate(float fraction, PointF startValue,
                        PointF endValue) {
                    // 估值计算方法---可以在执行的过程当中干预改变属性的值---做效果:用自己的算法来控制
                    //不断地去计算修改坐标
                    //x匀速运动 x=v*t 为了看起来效果好我让t变成fraction*5
                    pointF.x = 100f*(fraction*5);
                    //加速度 y=vt=1/2*g*t*t
    //              pointF.y = 0.5f*9.8f*(fraction*5)*(fraction*5);
                    pointF.y = 10f*0.5f*9.8f*(fraction*5)*(fraction*5);
                    return pointF;
                }
            });
            valueAnimator.addUpdateListener(new AnimatorUpdateListener() {
                
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    PointF f = (PointF) animation.getAnimatedValue();
                    iv.setX(f.x);
                    iv.setY(f.y);
                }
            });
            valueAnimator.start();
    

    ofObject方法使用

    1 创建point估值器,不断返回坐标变换值

    public class PointEvaluator implements TypeEvaluator{  
      
        @Override  
        public Object evaluate(float fraction, Object startValue, Object endValue) {  
            PointF startPoint = (Point) startValue;  
            PointF endPoint = (Point) endValue;  
            float x = startPoint.getX() + fraction * (endPoint.getX() - startPoint.getX());  
            float y = startPoint.getY() + fraction * (endPoint.getY() - startPoint.getY());  
            PointF point = new Point(x, y);  
            return point;  
        }  
    } 
    

    2 通过ofObject使用刚刚创建的估值器,从point1 到point2的移动

    Point point1 = new Point(0, 0);  
    Point point2 = new Point(300, 300);  
    ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), point1, point2);  
    anim.setDuration(5000);  
    anim.start();  
    

    动态改变View的颜色

    --------------------------------------------------------------------------
    public class MyAnimView extends View {  
      
        private String color;  
      
        public String getColor() {  
            return color;  
        }  
      
        public void setColor(String color) {  
            this.color = color;  
            mPaint.setColor(Color.parseColor(color));  
            invalidate();  
        }  
    }
    --------------------------------------------------------------------------
    ObjectAnimator anim = ObjectAnimator.ofObject(myAnimView, "color", new ArgbEvaluator(),   
        "#0000FF", "#FF0000");  
    anim.setDuration(5000);  
    anim.start(); 
    
    

    参考文档
    Android属性动画完全解析(上),初识属性动画的基本用法

    相关文章

      网友评论

          本文标题:属性动画一 基本使用

          本文链接:https://www.haomeiwen.com/subject/mrbhqxtx.html