Android中添加动画

动画简介

您可以通过动画添加视觉提示,向用户通知应用中的动态。当界面状态发生改变时(例如有新内容加载或有新操作可用时),动画尤其有用。动画还为应用增加了优美的外观,使其拥有更高品质的外观和风格。

Android 根据您需要的动画类型提供不同的动画 API,因此本页概括介绍了向界面添加动作的不同方法。

属性动画概述

属性动画系统是一个强健的框架,用于为几乎任何内容添加动画效果。您可以定义一个随时间更改任何对象属性的动画,无论其是否绘制到屏幕上。属性动画会在指定时长内更改属性(对象中的字段)的值。要添加动画效果,请指定要添加动画效果的对象属性,例如对象在屏幕上的位置、动画效果持续多长时间以及要在哪些值之间添加动画效果。

借助属性动画系统,您可以定义动画的以下特性:

  • 时长:您可以指定动画的时长。默认时长为 300 毫秒。
  • 时间插值:您可以指定如何根据动画的当前已播放时长来计算属性的值。
  • 重复计数和行为:您可以指定是否在某个时长结束后重复播放动画以及重复播放动画多少次。您还可以指定是否要反向播放动画。如果将其设置为反向播放,则会先播放动画,然后反向播放动画,直到达到重复次数。
  • Animator 集:您可以将动画分成多个逻辑集,它们可以一起播放、按顺序播放或者在指定的延迟时间后播放。
  • 帧刷新延迟:您可以指定动画帧的刷新频率。默认设置为每 10 毫秒刷新一次,但应用刷新帧的速度最终取决于整个系统的繁忙程度以及系统为底层计时器提供服务的速度。

属性动画的工作原理

首先,让我们通过一个简单的示例来了解动画的工作原理。图 1 描绘了一个假设的对象,该对象的 x 属性(表示其在屏幕上的水平位置)添加了动画效果。动画时长设置为 40 毫秒,要移动的距离为 40 像素。该对象每隔 10 毫秒(这是默认的帧刷新频率)会水平移动 10 像素。在 40 毫秒时,动画停止,同时对象在水平位置 40 处停止。这是使用线性插值(表示对象以恒定速度移动)的动画示例。


图 1. 线性动画示例

也可以指定动画使用非线性插值。图 2 展示了一个假设的对象,它在动画开始时加速,在动画结束前减速。该对象仍在 40 毫秒内移动了 40 像素,但这种移动是非线性的。开始时,此动画加速移动到中间点,然后从中间点减速移动,直至动画结束。如图 2 所示,动画在开头和结尾移动的距离小于在中间移动的距离。

图 2. 非线性动画示例

我们来详细了解一下属性动画系统的重要组成部分将如何计算如上所示的动画。图 3 描绘了主类之间是如何相互协作的。

图 3. 如何计算动画

ValueAnimator对象跟踪动画的时间,例如动画的已运行时长以及正在添加动画效果的属性的当前值。

ValueAnimator 包含 TimeInterpolatorTypeEvaluator;前者用于定义动画插值,后者用于定义如何计算正在添加动画效果的属性的值。例如,在图 2 中,所用的 TimeInterpolatorAccelerateDecelerateInterpolator,所用的 TypeEvaluatorIntEvaluator

要开始动画,请创建一个 ValueAnimator,并为您想要添加动画效果的属性赋予起始值和结束值,以及动画时长。当您调用 start() 时,动画即会开始播放。在整个动画播放期间,ValueAnimator 将基于动画时长和已播放时长计算已完成动画分数(在 0 和 1 之间)。已完成动画分数表示动画已完成时间的百分比,0 表示 0%,1 表示 100%。以图 1 为例,在 t = 10ms 处,已完成动画分数将为 0.25,因为总时长 t = 40ms。

ValueAnimator 计算完已完成动画分数后,它会调用当前设置的TimeInterpolator 来计算插值分数。插值分数会将已完成动画分数映射为一个新分数,该分数会考虑已设置的时间插值。例如,在图 2 中,由于动画缓慢加速,t = 10ms 时的插值分数(约 0.15)小于已完成动画分数 (0.25)。在图 1 中,插值分数始终等于已完成动画分数。

计算插值分数后,ValueAnimator 会调用相应的 TypeEvaluator,以根据动画的插值分数、起始值和结束值来计算要添加动画效果的属性的值。例如,在图 2 中,t = 10ms 时的插值分数为 0.15,因此,此时属性的值为 0.15 × (40 - 0),即 6。

属性动画与试图动画的区别

视图动画系统仅提供为View对象添加动画效果的功能,因此,如果您想为非 对象添加动画效果,则必须实现自己的代码才能做到。视图动画系统也存在一些限制,因为它仅公开 对象的部分方面来供您添加动画效果;例如,您可以对视图的缩放和旋转添加动画效果,但无法对背景颜色这样做。

视图动画系统的另一个缺点是它只会在绘制视图的位置进行修改,而不会修改实际的视图本身。例如,如果您为某个按钮添加了动画效果,使其可以在屏幕上移动,该按钮会正确绘制,但能够点击按钮的实际位置并不会更改,因此您必须通过实现自己的逻辑来处理此事件。

有了属性动画系统,您就可以完全摆脱这些束缚,还可以为任何对象(视图和非视图)的任何属性添加动画效果,并且实际修改的是对象本身。属性动画系统在执行动画方面也更为强健。概括地讲,您可以为要添加动画效果的属性(例如颜色、位置或大小)分配 Animator,还可以定义动画的各个方面,例如多个 Animator 的插值和同步。

不过,视图动画系统的设置需要的时间较短,需要编写的代码也较少。如果视图动画可以完成您需要执行的所有操作,或者现有代码已按照您需要的方式运行,则无需使用属性动画系统。在某些用例中,也可以针对不同的情况同时使用这两种动画系统。

API 概述

说明
ValueAnimator 属性动画的主计时引擎,它也可计算要添加动画效果的属性的值。它具有计算动画值所需的所有核心功能,同时包含每个动画的计时详情、有关动画是否重复播放的信息、用于接收更新事件的监听器以及设置待评估自定义类型的功能。为属性添加动画效果分为两个步骤:计算添加动画效果之后的值,以及对要添加动画效果的对象和属性设置这些值。ValueAnimator 不会执行第二个步骤,因此,您必须监听由 ValueAnimator 计算的值的更新情况,并使用您自己的逻辑修改要添加动画效果的对象。如需了解详情,请参阅使用 ValueAnimator 添加动画效果部分。
ObjectAnimator ValueAnimator的子类,用于设置目标对象和对象属性以添加动画效果。此类会在计算出动画的新值后相应地更新属性。在大多数情况下,您不妨使用 ObjectAnimator,因为它可以极大地简化对目标对象的值添加动画效果这一过程。不过,有时您需要直接使用 ValueAnimator,因为 ObjectAnimator存在其他一些限制,例如要求目标对象具有特定的访问器方法。
AnimatorSet 此类提供一种将动画分组在一起的机制,以使它们彼此相对运行。您可以将动画设置为一起播放、按顺序播放或者在指定的延迟时间后播放。如需了解详情,请参阅使用 AnimatorSet 编排多个动画部分。

评估程序负责告知属性动画系统如何计算指定属性的值。它们使用由 Animator 类提供的计时数据(即动画的起始值和结束值),并根据这些数据计算属性添加动画效果之后的值。属性动画系统可提供以下评估程序:

类/接口 说明
IntEvaluator 这是用于计算 int 属性的值的默认评估程序。
FloatEvaluator 这是用于计算 float 属性的值的默认评估程序。
ArgbEvaluator 这是用于计算颜色属性的值(用十六进制值表示)的默认评估程序。
TypeEvaluator 此接口用于创建您自己的评估程序。如果您要添加动画效果的对象属性不是 intfloat 或颜色,那么您必须实现 TypeEvaluator 接口,才能指定如何计算对象属性添加动画效果之后的值。如果您想以不同于默认行为的方式处理 intfloat和颜色,您还可以为这些类型的值指定自定义 TypeEvaluator。如需详细了解如何编写自定义评估程序,请参阅使用 TypeEvaluator 部分。

时间插值器指定了如何根据时间计算动画中的特定值。例如,您可以指定动画在整个动画中以线性方式播放,即动画在整个播放期间匀速移动;也可以指定动画使用非线性时间,例如动画在开始后加速并在结束前减速。表 3 介绍了 android.view.animation 中包含的插值器。如果下表提供的插值器都不能满足您的需求,请实现 TimeInterpolator 接口并创建您自己的插值器。如需详细了解如何编写自定义插值器,请参阅 使用插值器

类/接口 说明
AccelerateDecelerateInterpolator 该插值器的变化率在开始和结束时缓慢但在中间会加快。
AccelerateInterpolator 该插值器的变化率在开始时较为缓慢,然后会加快。
AnticipateInterpolator 该插值器先反向变化,然后再急速正向变化。
AnticipateOvershootInterpolator 该插值器先反向变化,再急速正向变化,然后超过定位值,最后返回到最终值。
BounceInterpolator 该插值器的变化会跳过结尾处。
CycleInterpolator 该插值器的动画会在指定数量的周期内重复。
DecelerateInterpolator 该插值器的变化率开始很快,然后减速。
LinearInterpolator 该插值器的变化率恒定不变。
OvershootInterpolator 该插值器会急速正向变化,再超出最终值,然后返回。
TimeInterpolator 该接口用于实现您自己的插值器。

使用AnimatorSet 编排多个动画

在许多情况下,您需要根据一个动画开始或结束的时间来播放另一个动画。借助 Android 系统,您可以将动画捆绑到一个 AnimatorSet 中,以便指定是同时播放动画、按顺序播放还是在指定的延迟时间后播放。您还可以相互嵌套 AnimatorSet 对象。

以下代码段通过以下方式播放相应的 Animator 对象:

  1. 播放 bounceAnim。
  2. 同时播放 squashAnim1、squashAnim2、stretchAnim1 和 stretchAnim2。
  3. 播放 bounceBackAnim。
  4. 播放 fadeAnim。
AnimatorSet bouncer = new AnimatorSet();
    bouncer.play(bounceAnim).before(squashAnim1);
    bouncer.play(squashAnim1).with(squashAnim2);
    bouncer.play(squashAnim1).with(stretchAnim1);
    bouncer.play(squashAnim1).with(stretchAnim2);
    bouncer.play(bounceBackAnim).after(stretchAnim2);
    ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
    fadeAnim.setDuration(250);
    AnimatorSet animatorSet = new AnimatorSet();
    animatorSet.play(bouncer).before(fadeAnim);
    animatorSet.start();
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,539评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,594评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,871评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,963评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,984评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,763评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,468评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,850评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,002评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,144评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,823评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,483评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,026评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,150评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,415评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,092评论 2 355

推荐阅读更多精彩内容