更流畅的动画框架-Additive Animation

1,873 阅读6分钟
原文链接: mp.weixin.qq.com
文章来源

http://www.jcodecraeer.com//a/anzhuokaifa/androidkaifa/2017/0806/8345.html

前言

在说明什么是additive animation之前,先用一个简单的演示来解释为什么要使用它。

用户触摸划动屏幕,黄色方块视图不断的随着手指在做移动动画。

注:基于新坐标与旧坐标之间的动画,而不是直接点哪到哪。

这里是使用标准Android动画系统的普通版本:

可以看到速度是被打断了的,当手指横跨整个屏幕的时候,view甚至不动-动画还没有运行就已经重新开始了。同样的交互使用additive animation是这样的:

Additive Animations

在我们的室内定位应用中,我们定期计算用户当前的位置(类似谷歌地图指示你位置的蓝色圆点),每当新位置计算出来的时候,我们用动画过渡到新的点,在Android中,这样会取消当前动画开始一个新的动画,从而导致不连贯的移动。iOS上实现这个功能一点问题都没有(因为iOS8之后每个基于 UIView的动画都是可以叠加执行的)

The API

虽然Google不久才发布的 physics-based animation API 可以实现类似的效果,但是他们的API需要对代码大幅改动,而且大多数情况下使用起来都笨重,不直观。

相反,让我们看一看前一个例子中的代码:

就是如此简单,如果觉得很熟悉,那是因为我有意让它接近ViewPropertyAnimator 的API,尽可能的让过渡更简单。

动画支持多种属性:

  • ViewPropertyAnimator 支持的所有属性( x, y, z, translationX, translationY, translationZ, rotation, alpha 等)

  • Margins, padding, size, elevation 以及具有恰当布局属性的view的滚动位置

  • 以ColorDrawable为背景的view的背景颜色

  • 几乎所有属性的Delta值 (ViewPropertyAnimator的*By() 方法).

  • 按照路径移动view

一个更复杂的例子

这里是一个稍微复杂的动画,涉及多个view,硬件层,延迟:

这是创建这个动画所需的代码:

这里发生了很多事情,让我们逐一分析:

withLayer() 为依次添加到动画的所有view启用了硬件动画。这个例子中的所有view都使用了小于1的透明度,以证明性能没有受到影响。得益于withLayer()以及AdditiveAnimator的高度优化,即使上百个动画同时运行也能如丝般顺滑。上面的例子中有800到1200个动画同时运行(可以秒杀大多数app了)。

target(View v)改变该动画作用的对象。对多个view使用动画无需使用AnimatorSet。

x(int x), y(int y), rotation(float degrees)为创建动画的方法,跟ViewPropertyAnimator的同类方法一样的作用。

最后一个方法- thenWithDelay(int millis)是AdditiveAnimator上我最喜欢的功能之一,值得单独讲解。

动画链

AnimatorSet最常见的使用场景之一是按序播放动画(除此之外还有同时播放动画)。

大体上,你需要这样做(感谢StackOverflow):

同样的动画,使用AdditiveAnimator来创建是这样的:

这里面的 then() 方法创建了一个新的AdditiveAnimator,与前面的那个是父-子关系,它拷贝了其所有属性(比如target,duration等),并且在它的内部把startOffset设置为前一个动画的duration(这里是700毫秒)。新的animator也可以根据需要配置和修改。

then()还有更多的功能,它们都比标准的动画API要方便很多:

  • thenAfterDelay(int millis) 上一个动画开始之后等待millis毫秒开始执行下一个动画。

  • thenBeforeEnd(int millis) 前一个动画结束之前多长时间开始。

  • thenAfterEnd(int millis) 前一个动画结束之后多久开始。

这里是这些方法在使用相同millis值时的效果比较:

thenAfterDelay(400),

 thenBeforeEnd(400) 

考虑到在一篇文章中介绍完内容太多,这只列出最主要功能得纲要。

AdditiveAnimator…

  • 可以通过继承来实现扩展。为子类暴露了一些必要的方法,如用于组合或者动画的方法。假设你在你的MyAnimator定义了一个 bounceTwice() :

  • 也可以不使用继承来动画自定义属性。通过为属性值定义一个getter 和 setter ,并提供自定义的TypeEvaluators来实现。下面是使用这它们为TextView的文字颜色应用动画的例子:

  • 无需使用AnimatorSet或者其它的封装就能实现多view同时动画

  • 可以沿路径动画-因为所有动画都是可以叠加的,你还可以同时沿几条路径动画,制造一个这样的动画。

  • 支持语法优雅的链式动画(then(), thenAfterDelay(int millis)等)。

  • 允许中途切换插值器(TimeInterpolator),比如当你想对位置执行弹簧动画,却不想让弹跳影响到透明度值的时候,这个特性就非常有用。

  • automatically handles shortest-distance rotation computation for you (never worry about computing the shortestangle again).

  • 支持硬件层动画,使用熟悉的 withLayer() 语法。

  • 包含直观的标准API,比如动画的取消(所有或者特定的动画),添加多个 start/end/update listener,设置重复模式/次数,获得当前动画作用的对象(或者还没有开始的队列中的动画对象)。

  • 如果没有指定值的话,将使用全局的默认值(比如TimeInterpolator 或者 animation duration)。

要在一篇文章中介绍完这些特性内容就长了,所以详情还是看demo源码。

如何使用

点击下方空白区域查看答案

「手机上看不见我」  


可插入其他样式内容,高度固定180px,可通过修改代码的方式调整区域高度!

该库支持API Level 14+ (Android 4.0+)。库源码以及demo演示的源码见GitHub,如果要在项目中引用此库,在 build.gradle 文件中添加:

精选文章推荐

点击下方空白区域查看答案

「手机上看不见我」  


可插入其他样式内容,高度固定180px,可通过修改代码的方式调整区域高度!

  1. 程序员成为自由职业者靠谱么?

  2. Android 中基于物理特性的动画简介

  3. 技术面试九忌

每天为你推送Android干货和最新、最鲜、最有料的互联网科技资讯!   

AndroidParks 长按识别二维码,或微信搜索androidparks Android技术分享群:534813930