Android 属性动画——插值器、估值器、关键帧
   动画中除了一些简单和组合的动画效果,还有很多其它的小功能,比如说这里的插值器、估值器、关键帧。
    插值器 
    对 Android 动画来说,不管是视图动画还是属性动画,都是有插值器的,那什么是插值器呢?就是控制动画随着时间轴的变化而变换的效果。
    而 Android 动画也自带了一些插值器,如:加速插值器、减速插值器、循环插值器等等,接下来我们看看 Android 动画自带的插值器,我们以循环插值器为例:
    代码:
    // 设置自带插值器
        private void setInterpolator(){
            ObjectAnimator animator = ObjectAnimator.ofFloat(imageView,"translationX",0f,200f);
            animator.setDuration(2000);
            // 设置自带的循环差值器,循环 2 次
            animator.setInterpolator(new CycleInterpolator(2));
            animator.start();
        }
    看一下效果:
    我们来看一下它的源码,先看一下 setInterpolator() 方法的源码:
    @Override
        public void setInterpolator(TimeInterpolator value) {
            if (value != null) {
                mInterpolator = value;
            } else {
                mInterpolator = new LinearInterpolator();
            }
        }
    可以看到,它是在为 mInterpolator 赋值,那么什么时候会用到 mInterpolator 呢?我们继续看看:
    void animateValue(float fraction) {
            fraction = mInterpolator.getInterpolation(fraction);
            mCurrentFraction = fraction;
            int numValues = mValues.length;
            for (int i = 0; i < numValues; ++i) {
                mValues[i].calculateValue(fraction);
            }
            if (mUpdateListeners != null) {
                int numListeners = mUpdateListeners.size();
                for (int i = 0; i < numListeners; ++i) {
                    mUpdateListeners.get(i).onAnimationUpdate(this);
                }
            }
        }
    我们可以看到,上面这个方法中使用了 mInterpolator  的 getInterpolation() 方法,并把获取到的值赋给了动画的属性,那么我们看看 CycleInterpolator 的 getInterpolation() 方法:
    public float getInterpolation(float input) {
            return (float)(Math.sin(2 * mCycles * Math.PI * input));
        }
    我们看到,其实就是随着传进来的值,再返回一个随着公式变化的值,而这个 input 就代表着时间,0.0f 表示动画开始时,1.0f 表示动画结束时。
    既然我们知道了这个是怎么实现的,那我们就可以自己来实现一个插值器,我们新建一个 MyInterpolator 实现 Interpolator 接口,重写 getInterpolation() 方法,然后自己找一个公式:
    public class MyInterpolator implements Interpolator {
        @Override
        public float getInterpolation(float input) {
            // 这里我们使用高中经常使用的正弦表达式
            return (float) (2*Math.sin(2*Math.PI*input+0.5f*Math.PI));
        }
    }
    然后我们给动画设置我们自定义的插值器,来看看效果:
    可以看到,我们已经实现了我们自定义的插值器。
    估值器
    说了插值器了,那什么是估值器呢?插值器是通过时间来得到位置,并对其进行操作的一种功能,那么估值器与之对应,估值器是返回动画当前时间的属性值,让我们来进行有些操作。
    Android 动画中也有自带的估值器,如 FloatEvaluator、IntEvaluator 等等,在 API 21,Android 5.0 以后也推出了 PointFEvaluator,返回一个点的属性,可以对其 X 轴、Y 轴同时进行操作,那么如果是 Android 5.0  以前呢?我们要怎么来实现它呢?所以接下来我们通过自定义一个 PointEvaluator 来了解一下估值器的使用:
    首先我们定义一个 PointT.java 文件:
    public class PointT {
        // 横纵坐标
        private float x;
        private float y;
     
        public PointT(float x,float y){
            this.x = x;
            this.y = y;
        }
     
        public float getX() {
            return x;
        }
     
        public void setX(float x) {
            this.x = x;
        }
     
        public float getY() {
            return y;
        }
     
        public void setY(float y) {
            this.y = y;
        }
    }
    接下来,我们定义一个 PointTEvaluator.java 实现 TypeEvaluator<PointTEvaluator> 接口,重写 evaluate() 方法:
    public class PointTEvaluator implements TypeEvaluator<PointT> {
     
        // 传进来的 fraction 为动画已经运行的时间,0.0 为开始,1.0 为结束
        // startValue 为动画起始点坐标,endValue 为动画结束点坐标
        @Override
        public PointT evaluate(float fraction, PointT startValue, PointT endValue) {
            // X 轴已运行距离
            float d = fraction*(endValue.getX()-startValue.getX());
            // 设置 X 轴坐标,为起始 X 坐标加上已经运动的 X 距离
            float x = startValue.getX()+d;
            // Y 轴按照正弦函数图像运行,d/200 是为了防止像素过大,运动出边界
            // * 200 是因为正弦函数值域为 -1 到 1,像素大小无法分辨动画
            float y = (float) (startValue.getY() + (Math.sin((d/200)*Math.PI)) * 200);
            return new PointT(x,y);
        }
    }
    接下来我们来设置估值器:
    // 设置估值器
        private void setEvaluator(){
            ValueAnimator animator = new ValueAnimator();
            animator.setDuration(2000);
            // 设置起止属性
            animator.setObjectValues(new PointT(imageView.getX(),imageView.getY()),
                    new PointT(imageView.getX()+400f,imageView.getY()));
            // 设置估值器
            animator.setEvaluator(new PointTEvaluator());
            // 设置动画更新监听器
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    // 拿到估值器设置的 X、Y
                    PointT pointT = (PointT) animation.getAnimatedValue();
                    // 为 imageView 设值
                    imageView.setX(pointT.getX());
                    imageView.setY(pointT.getY());
                }
            });
            animator.start();
        }
    来看看效果图:
    可以看到,我们平移的时候,图像按照我们想要正弦函数图像运动,那么估值器的简单使用就是这样,还有一种写法来实现这个估值器,我们看看,比较容易懂就不做注解了:
    /**
              * 第二种方法设置估值器
             */
            animator.setEvaluator(new TypeEvaluator<PointT>() {
                @Override
                public PointT evaluate(float fraction, PointT startValue, PointT endValue) {
                    float d = fraction*(endValue.getX()-startValue.getX());
                    float x = startValue.getX()+d;
                    float y = (float) (startValue.getY() + (Math.sin((d/200)*Math.PI)) * 200);
                    return new PointT(x,y);
                }
     
            });
    关键帧
    说了插值器和估值器,那么什么是关键帧呢?先看一组代码:
    private void keyFrame(){
            Keyframe keyframe1 = Keyframe.ofFloat(0,0);
            Keyframe keyframe2 = Keyframe.ofFloat(0.25f,200);
            Keyframe keyframe3 = Keyframe.ofFloat(0.75f,100);
            Keyframe keyframe4 = Keyframe.ofFloat(1,300);
            PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("translationX",keyframe1,keyframe2,keyframe3,keyframe4);
            ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(imageView,holder);
            animator.setDuration(2000);
            animator.start();
        }
    然后放效果图:
      可以看到,我们的动画先向前,再向后,又向前,所以我们的代码什么意思呢?我们来看一下 Keyframe.ofFloat() 这个方法:
    public static Keyframe ofFloat(float fraction, float value) {
            return new FloatKeyframe(fraction, value);
        }
    这个方法有两个参数,一个 fraction,上面我们经常使用这个参数,相信大家已经知道了,这个就是动画运行的时间,0.0 表示动画开始时,1.0 表示动画结束时,value 表示属性,这个方法就是说在给动画定义一些关键的节点赋予属性来实现动画。
    好了,插值器、估值器和关键帧的简单讲解就是这么多,主要是提供一个思路,大家可以按照自己的需求实现更加复杂丰富的动画效果。
    项目地址:源代码
--------------------- 
作者:Young_Time 
来源:CSDN 
原文:https://blog.csdn.net/Young_Time/article/details/80888799 
版权声明:本文为博主原创文章,转载请附上博文链接!
 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号