Android动画:Interpolator插值器使用和自定义详解

时间:2022-09-06 18:34:05

Android动画:Interpolator插值器使用和自定义详解

前言

属性动画可以对某个属性做动画,而插值器(TimeInterpolator)和估值器(TypeEvaluator)在其中扮演了重要角色;

那么今天我们了解下 插值器TimeInterpolator;

一、插值器介绍

1、Interpolator有什么用

  • Interpolator 被用来修饰动画效果,定义动画的变化率;
  • 在Android源码中对应的接口类为TimeInterpolator,通过输入均匀变化的0~1之间的值;
  • 可以得到匀速、正加速、负加速、无规则变加速等0~1之间的变化曲线;

2、应用场景

  • 实现非线性运动的动画效果;
  • 非线性运动是指动画改变的速率不是一成不变的,如加速、减速运动的动画效果;
  • 实现复杂的曲线动画,回弹效果自定义等都需要自定义插值器;

3、Android系统提供的插值器类型

  • AccelerateDecelerateInterpolator 在动画开始与结束比较慢,中间加速
  • AccelerateInterpolator 加速
  • AnticipateInterpolator 开始的时候向后然后向前甩
  • AnticipateOvershootInterpolator 开始的时候向后然后向前甩一定值后返回最后的值
  • BounceInterpolator 动画结束的时候弹起
  • CycleInterpolator 动画循环播放特定的次数,速率改变沿着正弦曲线
  • DecelerateInterpolator 减速
  • LinearInterpolator 以常量速率改变
  • OvershootInterpolator 向前甩一定值后再回到原来位置

二、插值器应用

插值器的使用有两种方式:在XML和代码中使用

1、xml

XML动画文件使用插值器时,需要设置系统设置的对应的插值器资源ID

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <set xmlns:android="http://schemas.android.com/apk/res/android"
  3.     <alpha 
  4.         android:fromAlpha="1.0" 
  5.         android:toAlpha="0.1" 
  6.         android:duration="2000" 
  7.         android:repeatMode="reverse" 
  8.         android:repeatCount="infinite" 
  9.         android:interpolator="@android:anim/linear_interpolator"/> 
  10. </set

2、代码中使用

  • 代码使用插值器时,只需创建对应的插值器对象,然后设置给动画对象;也可以加载xml文件中配置的插值器;
  • 利用view的setInterpolator(Context context, @AnimRes @InterpolatorRes int resID)设置插值器;
  1. //创建一个渐变透明度的动画,从透明到完全不透明 
  2. AlphaAnimation alphaAnimation = new AlphaAnimation(0.1f, 1.0f); 
  3. //设置动画时长 
  4. alphaAnimation.setDuration(5000); 
  5. //设置动画重复方式 
  6. alphaAnimation.setRepeatMode(AlphaAnimation.REVERSE); 
  7. //设置动画播放次数 
  8. alphaAnimation.setRepeatCount(AlphaAnimation.INFINITE); 
  9. //设置匀速插值器 
  10. alphaAnimation.setInterpolator(new LinearInterpolator()); 
  11. //为View开启指定类型动画 
  12. imageView.startAnimation(alphaAnimation) 
  • 使用Android内置的插值器能满足大多数的动画需求;
  • 如果系统提供的插值器无法满足需求,还可以自定义插值器;

三、自定义插值器

1、实现方式

  • 自定义插值器需要实现Interpolator或TimeInterpolator接口,并复写getInterpolation()方法;
  • 补间动画 实现 Interpolator接口;属性动画实现TimeInterpolator接口;
  • TimeInterpolator接口是属性动画中新增的,用于兼容Interpolator接口,这使得所有过去的Interpolator实现类都可以直接在属性动画使用;

Interpolator接口和TimeInterpolator接口说明如下:

  1. // Interpolator接口 
  2. public interface Interpolator {   
  3.     // 内部只有一个方法:getInterpolation() 
  4.      float getInterpolation(float input) {   
  5.         // 参数说明 
  6.         // input值值变化范围是0-1,且随着动画进度(0% - 100% )均匀变化 
  7.         // 即动画开始时,input值 = 0;动画结束时input = 1 
  8.         // 而中间的值则是随着动画的进度(0% - 100%)在0到1之间均匀增加 
  9.       ...// 插值器的计算逻辑 
  10.       return xxx; 
  11.       // 返回的值就是用于估值器继续计算的fraction值,下面会详细说明 
  12.     }   
  13. // TimeInterpolator接口 
  14. public interface TimeInterpolator {   
  15.     float getInterpolation(float input){ 
  16. // input值值变化范围是0-1,且随着动画进度(0% - 100% )均匀变化 
  17.       ...// 插值器的计算逻辑 
  18.     };   
  19. }   

自定义插值器的关键在于:对input值根据动画的进度(0%-100%)通过逻辑计算从而计算出当前属性值改变的百分比;

2、自定义插值器

写一个自定义Interpolator:先减速后加速

  1. /* 
  2.  * 根据需求实现Interpolator接口 
  3.  * TestInterpolator.java 
  4.  */ 
  5. public class TestInterpolator implements TimeInterpolator { 
  6.     @Override 
  7.     public float getInterpolation(float input) { 
  8.         float result; 
  9.         if (input <= 0.5) { 
  10.             result = (float) (Math.sin(Math.PI * input)) / 2; 
  11.             // 使用正弦函数来实现先减速后加速的功能,逻辑如下: 
  12.             // 因为正弦函数初始弧度变化值非常大,刚好和余弦函数是相反的 
  13.             // 随着弧度的增加,正弦函数的变化值也会逐渐变小,这样也就实现了减速的效果。 
  14.             // 当弧度大于π/2之后,整个过程相反了过来,现在正弦函数的弧度变化值非常小,渐渐随着弧度继续增加,变化值越来越大,弧度到π时结束,这样从0过度到π,也就实现了先减速后加速的效果 
  15.         } else { 
  16.             result = (float) (2 - Math.sin(Math.PI * input)) / 2; 
  17.         } 
  18.         return result; 
  19.         // 返回的result值 = 随着动画进度呈先减速后加速的变化趋势 
  20.     } 
  21. /* 
  22.  * 步骤设置使用 
  23.  * Test.java 
  24.  */ 
  25.  //  创建动画作用对象:此处以Button为例 
  26.  mButton = (Button) findViewById(R.id.Button); 
  27.  //  获得当前按钮的位置 
  28. float curTranslationX = mButton.getTranslationX(); 
  29. //  创建动画对象 & 设置动画 
  30. ObjectAnimator animator = ObjectAnimator.ofFloat(mButton, "translationX", curTranslationX, 300,curTranslationX); 
  31. // 表示的是: 
  32. // 动画作用对象是mButton 
  33. // 动画作用的对象的属性是X轴平移 
  34. // 动画效果是:从当前位置平移到 x=1500 再平移到初始位置 
  35. //  设置步骤1中设置好的插值器:先减速后加速 
  36. animator.setInterpolator(new TestInterpolator()); 
  37. // 启动动画 
  38. animator.start(); 

3、贝塞尔曲线的插值器

Android动画:Interpolator插值器使用和自定义详解

(1)先使用贝塞尔曲线数值生成工具来获取想要的曲线数值

  • 工具网站:https://cubic-bezier.com/;
  • 拉拽左边图像的2个点,调整出符合效果的图形;
  • 点击Go按键,可看到红色与蓝色的方块运动状态,调节自己想要的效果;
  • 将4个参数运用到下面的代码中;

(2)代码运用

  1. ObjectAnimator animator = ObjectAnimator.ofFloat(mButton, "translationX", curTranslationX, 300,curTranslationX); 
  2. EaseCubicInterpolator interpolator = new EaseCubicInterpolator(0.31f, 0.85f,0.77f, 0.14f); 
  3. animator.setInterpolator(interpolator) 

(3)贝塞尔曲线插值器

  1. import android.graphics.PointF; 
  2. import android.view.animation.Interpolator; 
  3. /** 
  4.  * 缓动三次方曲线插值器.(基于三次方贝塞尔曲线) 
  5.  */ 
  6. public class EaseCubicInterpolator implements Interpolator { 
  7.     private final static int ACCURACY = 4096; 
  8.     private int mLastI = 0; 
  9.     private final PointF mControlPoint1 = new PointF(); 
  10.     private final PointF mControlPoint2 = new PointF(); 
  11.     /** 
  12.      * 设置中间两个控制点 
  13.      * 
  14.      * 在线工具: http://cubic-bezier.com 
  15.      * 
  16.      * @param x1 
  17.      * @param y1 
  18.      * @param x2 
  19.      * @param y2 
  20.      */ 
  21.     public EaseCubicInterpolator(float x1, float y1, float x2, float y2) { 
  22.         mControlPoint1.x = x1; 
  23.         mControlPoint1.y = y1; 
  24.         mControlPoint2.x = x2; 
  25.         mControlPoint2.y = y2; 
  26.     } 
  27.     @Override 
  28.     public float getInterpolation(float input) { 
  29.         float t = input; 
  30.         // 近似求解t的值[0,1] 
  31.         for (int i = mLastI; i < ACCURACY; i++) { 
  32.             t = 1.0f * i / ACCURACY; 
  33.             double x = cubicCurves(t, 0, mControlPoint1.x, mControlPoint2.x, 1); 
  34.             if (x >= input) { 
  35.                 mLastI = i; 
  36.                 break; 
  37.             } 
  38.         } 
  39.         double value = cubicCurves(t, 0, mControlPoint1.y, mControlPoint2.y, 1); 
  40.         if (value > 0.999d) { 
  41.             value = 1; 
  42.             mLastI = 0; 
  43.         } 
  44.         return (float) value; 
  45.     } 
  46.     /** 
  47.      * 求三次贝塞尔曲线(四个控制点)一个点某个维度的值.<br> 
  48.      * <p> 
  49.      * 
  50.      * @param t      取值[0, 1] 
  51.      * @param value0 
  52.      * @param value1 
  53.      * @param value2 
  54.      * @param value3 
  55.      * @return 
  56.      */ 
  57.     public static double cubicCurves(double t, double value0, double value1, 
  58.                                      double value2, double value3) { 
  59.         double value; 
  60.         double u = 1 - t; 
  61.         double tt = t * t; 
  62.         double uu = u * u; 
  63.         double uuu = uu * u; 
  64.         double ttt = tt * t; 
  65.         value = uuu * value0; 
  66.         value += 3 * uu * t * value1; 
  67.         value += 3 * u * tt * value2; 
  68.         value += ttt * value3; 
  69.         return value; 
  70.     } 

总结

要实现复杂的动画效果时,就要自定义插值器,其实插值器还是的学习算法;

大家一起加油;

原文链接:https://mp.weixin.qq.com/s/ZKYECerXThW3MQyJkZcDIw