有关Android动画部分的内容应该已经写过四篇相关文章了,它们分别是:
其中,后两篇是介绍的属性动画相关部分,今天这篇文章所介绍的重点是动画插值器Interpolator,事实上动画插值器并不仅仅使用在属性动画上面,前面介绍补间动画的时候也使用过动画插值器Interpolator。简单说介绍一下什么是动画插值器Interpolator,动画从初始状态到结束状态进行过渡,在过渡过程中所采用的的一系列值就是插值,动画的执行时间点在时间上并不是连续的,它是在一个间断性取值的过程,人眼一秒钟可以观测到24帧,只要在一秒钟的时间内采集插值超过24次,我们所能看到的动画就是连续的。
插值器Interpolator的主要作用是控制动画变化的速率,上一篇文章介绍TypeEvaluator的时候介绍过,TypeEvaluator的核心算法是计算动画从初始值到结束值的一个线性变化取值,将TypeEvaluator的计算值与插值器Interpolator的取值进行乘法运算就决定了动画的执行状态,可以这么理解就是插值器Interpolator决定了动画加速还是减速又或者是线性的变化,插值器Interpolator取值范围一般为[0,1]。
Interpolator翻译成插值器,Android中它的底层实现如下:
Java
public interface TimeInterpolator { float getInterpolation(float input); }
public interface TimeInterpolator { float getInterpolation(float input); }
TimeInterpolator是在Android API 11中新加入的,在之前就叫做Interpolator,在TimeInterpolator接口中只有一个方法getInterpolation需要实现,方法的返回值就是插值,插值可以大于1,也可以小于0,所以上面说Interpolator取值范围一般为[0,1],大于1或者小于0的情况也很常见,比如回弹效果。参数input的取值是[0,1]。
下面是Interpolator的代码实现:
Java
public interface Interpolator extends TimeInterpolator { }
public interface Interpolator extends TimeInterpolator { }
Interpolator仅仅继承了TimeInterpolator没有做任何事情。
动画如果不设置插值器Interpolator,默认采用的是一个先加速后减速的插值器AccelerateDecelerateInterpolator。
系统已经内置了许多插值器,API 22中的如下:
插值器Interpolator位于android.view.animation包下,为了验证插值器的二次曲线效果,有两个网址可以帮助我们实时查看 inloop.github.io/interpolator/ 和 www.wolframalpha.com/ 。
函数:y=t;
下图是动画及插值取点的动态图:
我们在开发过程中对动画的处理最常见的还是对View的处理,属性动画操作相对来说比补间动画已经简单了许多,那么面对最常见的View的动画处理是不是仍然有更简单的处理方式呢?这个答案是肯定的,就在 ViewPropertyAnimator类中,接下来通过一个例子进行对比介绍。
ViewPropertyAnimator是在Android3.1版本推出的,它不是什么高级类,只是为了更简单方面的操作View,因为多数动画都是针对View,Google开发团队也意识到了这一点,于是一个简约而不简单的动画操作类ViewPropertyAnimator就诞生了。
如果我们想将一个图片在x方向平移100像素,在y方向平移200像素,在上一篇文章中我们将结果组合动画可以将单个动画进行组合播放,可以设计两个动画,一个动画进行x方向平移,另一个动画进行y方向平移,这也是最容易想到的一种解决方式了。
Java
ObjectAnimator animX = ObjectAnimator.ofFloat(imageView, "x", 100f); ObjectAnimator animY = ObjectAnimator.ofFloat(imageView, "y", 200f); AnimatorSet animSetXY = new AnimatorSet(); animSetXY.playTogether(animX, animY); animSetXY.start();
ObjectAnimatoranimX = ObjectAnimator.ofFloat(imageView, "x", 100f); ObjectAnimatoranimY = ObjectAnimator.ofFloat(imageView, "y", 200f); AnimatorSetanimSetXY = new AnimatorSet(); animSetXY.playTogether(animX, animY); animSetXY.start();
组合动画AnimatorSet确实可以实现效果,可是我们也发现了,如果我们一个特效用到平移旋转再加上透明度的变化,仅仅一个动画我们就要定义好几个ObjectAnimator对象,逻辑上虽然清晰但是结构确实有些冗余了。
在Android中如果要实现单个对象不同属性的动画效果,可以使用组合动画AnimatorSet之外,我们还可以使用PropertyValuesHolder来实现,具体做法如下:
Java
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 100f); PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 200f); ObjectAnimator.ofPropertyValuesHolder(imageView, pvhX, pvhY).start();
PropertyValuesHolderpvhX = PropertyValuesHolder.ofFloat("x", 100f); PropertyValuesHolderpvhY = PropertyValuesHolder.ofFloat("y", 200f); ObjectAnimator.ofPropertyValuesHolder(imageView, pvhX, pvhY).start();
PropertyValuesHolder用于保存单个属性的动画效果,在使用上大致分为以下三个步骤:
上面虽然只使用了一个ObjectAnimator,但是跟组合动画比较起来也是伯仲之间,代码结构也不简单,下面才是最简单的实现方式。
ViewPropertyAnimator将图片平移一行代码就搞定了,代码如下:
Java
imageView.animate().x(100f).y(200f);
imageView.animate().x(100f).y(200f);
上面代码中感觉并没有使用到ViewPropertyAnimator类,事实上该类是借助View的animate方法返回的,然后我们就可以直接调用动画方法了,每一个动画方法都是返回的ViewPropertyAnimator实例,该种实现方式跟Builder建造者模式差不多,每次调用之后都返回自己。
在使用ViewPropertyAnimator时,我们自始至终没有调用过start()方法,这是因为新的接口中使用了隐式启动动画的功能,只要我们将动画定义完成之后,动画就会自动启动。并且这个机制对于组合动画也同样有效,只要我们不断地连缀新的方法,那么动画就不会立刻执行,等到所有在ViewPropertyAnimator上设置的方法都执行完毕后,动画就会自动启动。当然如果不想使用这一默认机制的话,我们也可以显式地调用start()方法来启动动画。
Android动画方面的相关笔记到今天为止已经5篇了,接下来还想再补上一篇,是一篇针对更高API动画特效的介绍,就是在MetrialDesign中常用的部分特效。动画部分知识点暂时记录到这个深度,随着开发水平不断增进将来还会继续查漏补缺,针对动画部分的理解应用目前还是停留在表面,如果想要在实际项目中融会贯通详细还需要一些时间的沉淀,好吧,就这么多……