Android属性动画Property Animation.docx
《Android属性动画Property Animation.docx》由会员分享,可在线阅读,更多相关《Android属性动画Property Animation.docx(15页珍藏版)》请在冰豆网上搜索。
Android属性动画PropertyAnimation
属性动画系统是一个健壮的框架,它几乎可以允许把任何对象变成动画。
可以根据时间的推移来改变任何对象的属性来定义一个动画,而不用关心该对象是否要绘制在屏幕上。
属性动画是在指定的时间长度上改变一个属性(对象中的一个成员字段)的值。
要让某些对象变成动画,就要给该对象指定想要的动画属性,如果对象在屏幕上的位置、动画的停留时间以及动画之间的值等。
属性动画系统可以定义以下动画特性:
1.持续时间(Duration):
指定动画的持续时间。
默认长度是300毫秒。
2.时间插值(Timeinterpolation):
这个值能够做为计算当前动画运行时间的函数的属性值来指定,它决定动画的变化频率。
3.重复次数和行为(Repeatcountandbehavior)
这个属性能够指定在动画结束时是否重新播放动画,以及重复播放的次数。
还能够指定动画是否能够反向回播,如果设置了反向回播,那么动画就会先向前再向后,重复播放,直到达到播放次数。
4.动画集合(Animatorsets):
你能够把动画组织到一个逻辑集合中,然后或者同时、或者顺序的、或者延迟播放它们。
5.帧刷新延迟(Framerefreshdelay):
你能够指定动画帧的刷新频率。
默认是每10秒中刷新一次,但是应用程序最终的刷新帧的速度依赖与系统的繁忙程度以及系统能够提供的底层定时器的反应速度。
属性动画是如何工作的
首先,让我们用一个简单的例子来看一下动画的工作方式。
图1绘制了一个假想的动画对象,它用x属性来表示其在屏幕上的水平位置。
动画的持续时间被设置为40毫秒,并且移动的距离是40个像素。
每10毫秒,是默认的帧刷新频率,即每10毫秒对象水平移动10个像素。
在40毫秒结束时,动画停止,并且动画要停留在水平40像素点的位置上。
这是一个线性插值的动画示例,意味着动画匀速运动。
图1.线性动画示例
还可以指定非线性差值的动画。
图2假设了一个加速开始、减速结束的动画对象,该对象依然在40毫秒内移动了40个像素,但是非线性的。
在开始的时候,这个动画加速运动到一半的位置,然后开始减速运动直到动画结束。
如图2所示,对象运行的距离在开始和结束阶段要比中间部分短。
图2.非线性动画的示例
接下来让我们更详细的了解属性动画系统的重要组件是如何计算上图所示动画。
图3绘制了主类和其他类是如何一起工作的。
图3.动画的计算方式
ValueAnimator对象保持着动画的时间轨迹,如动画的运行时间,以及动画属性的当前值。
ValueAnimator类封装了一个TimeInterpolator类,这个类定义了动画的差值,和一个TypeEvaluator类,这个类定义动画属性值的计算方式。
例如,在图2中TimeInterpolator对象使用AccelerateDecelerateInterpolator定义,TypeEvaluator使用了IntEvaluator定义。
要启动一个动画,就要创建一个ValueAnimator对象,并且要给该对象设置想要的动画的属性的开始和结束值,以及动画的持续时间。
在调用start()方法开始动画的时候,整个动画期间,ValueAnimator对象会根据动画的持续时间和已经执行的时间,在0和1之间,计算一个elapsedfraction(过去系数)。
这个系数代表了动画已经完成的百分比,0意味着0%、1意味着100%。
例如,图1中,在t=10毫秒处的过去系数是0.25,因为总的持续时间是t=40毫秒。
当ValueAnimator对象完成过去系数的计算时,它会调用当前设置的TimeInterpolator对象,来计算一个差值系数(interpolatedfraction)。
差值系数(interpolatedfraction)把过去系数(elapsedfraction)映射到一个新的考虑设置时间差值的系数。
例如,在图2中,因为动画是慢慢的加速,因此在t=10毫秒时,差值系数大约是0.15,它比过去系数(elapsedfraction)0.25要小。
在图1中,差值系数(interpolatedfraction)与过去系数(elapsedfraction)始终相同。
在计算差值系数(interpolatedfraction)时,ValueAnimator对象会调用相应的TypeEvaluator对象,基于差值系数、动画的开始值、结束值,来计算动画的属性值。
例如,在图2中,在t=10毫秒处,差值系数是0.15,因此在此时的属性值应该是0.15*(40–0)=6。
在APIDemos示例工程中的com.example.android.apis.animation包,提供了很多如何使用属性动画系统的例子。
(
属性动画与视图动画的差异
视图动画提供了只让View对象具有动画效果的能力,因此想要非View对象具有动画效果,就得自己实现动画效果的代码。
事实上,视图动画系统也受到了限制,它只会把很少的View对象的特征暴露给动画效果,如例如,View对象的缩放和旋转,但是没有背景色,等等。
视图动画的另一个缺点是,它仅能够在绘制View对象时被修改,并且不是实际的View对象本身。
例如,如果要让一个按钮,以动画的形式穿越屏幕,按钮正确的绘制了,但是点击按钮的实际位置却不会改变,因此必须自己来实现这种处理逻辑。
在属性动画系统中,这些现在被彻底删除,并且能够让任何对象的任何属性具有动画效果(View对象和非View对象),并且能够实际修改对象自身。
属性动画在动画执行方面也更加健壮。
在高层次上,可以给想要动画效果的属性分配动画执行器,如颜色、位置、尺寸以及能够定义的动画特性(如插值和多个动画的同步等)。
但是,视图动画系统需要较少的创建时间和编写较少的代码。
如果视图动画能够满足需求,或者既存的代码已经做了想要完成的动画效果,就不需要使用属性动画效果了。
针对不同的情况来选择使用这两种不同的动画系统。
API概要
在android.animation包中能够找大多数属性动画系统的API。
因为视图动画系统已经在android.view.animation包中定义了很多插值,因此在属性动画系统中也能够使用这些插值。
下列表格中介绍了属性动画系统的主要组件。
Animator类提供了创建动画的基本架构。
通常不会直接使用这个类,因为它只提供了基本功能,因此要完全的支持动画值就必须扩展这个类,下表列出了Animator的子类。
表1.Animators
类
说明
ValueAnimator
用于计算处理动画属性值的主要属性动画时序引擎。
它有所有的计算动画值的核心功能,并包含了每个动画的时序细节、动画是否重复的信息、监听接收更新事件和设置评估定制类型的能力。
有两类动画属性:
1.计算动画处理的值;2.把这些值设置到要进行动画处理的对象和属性上。
ValueAnimator类不执行第二类属性,因此必须通过ValueAnimator对象来监听被计算值的变化,并且要自己修改想要的动画对象的逻辑。
更多的信息请看用ValueAnimator类来进行动画处理。
(
ObjectAnimator
ValueAnimator类的一个子类,它允许给目标对象和对象属性设置动画。
这个类在计算新的动画值的时候,会更新属性的坐标。
大多数时候都会使用ObjectAnimator类,因为它使得动画值的处理更加容易。
但是,有些时候也会直接使用ValueAnimator类,因为ObjectAnimator类有更多的限制,如在目标对象上需要指定用于呈现的acessor方法。
AnimatorSet
提供了一种把动画组织到一起的机制,以便它们能够彼此相互关联的运行。
你能够设置动画在一起播放、顺序的播放、或者在指定的延时之后播放。
更多的信息请看“用AnimatorSets来编排多个动画”
评价器会告诉属性动画系统如何计算给定属性的值。
它们利用Animator类提供时序数据:
动画的开始和结束值,以及基于这些数据计算得来的属性动画值。
属性动画系统提供了下列评价器:
表2.Evaluators
Class/Interface
说明
IntEvaluator
默认的用于评价int类型属性计算值的评价器
FlaoatEvaluator
默认的用于评价float类型属性计算值的评价器
ArgbEvaluator
默认的用于评价颜色属性计算值的评价器,颜色属性值用十六进制表示。
TypeEvaluator
允许创建自定义评价器的接口。
如果要让一个非int、float、颜色类型的属性具有动画效果,就必须实现这个TypeEvaluator接口,用它来指定如何计算对象属性动画值。
如果想要处理有别于int、float和颜色类型默认行为的动画,也能够给它们指定一个自定义的TypeEvaluator。
如何编写自定义的评价器,请看“使用TypeEvaluator”
时间差值给动画中的时间函数定义了一个用于计算的具体的值。
例如,一个线性过渡的动画,意味着整个动画期间动画都会均匀的移动,或者例如加速开始,减少结束的非线性动画。
表3介绍了被包含在android.view.animation包中差值。
如果那里没有适合你需要的差值,你可以实现TimeInterpolator接口,创建自己的差值。
如何编写自定义差值的更多信息,请看“使用差值”。
表3.Interpolators
Class/Interface
说明
AccelerateDecelerateInterpolator
变化频率在开始和结尾处慢,而在中间部分加速
AccelerateInterpolator
变化频率在开始慢,然后加速
AnticipateInterpolator
先向后,然后向前抛出(抛物运动)
AnticipateOvershootInterpolator
先向后,向前抛出并超过目标值,然后最终返回到目标值。
BounceInterpolator
在结束时反弹
CycleInterpolator
用指定的循环数,重复播放动画
DecelerateInterpolator
变化频率是快出,然后减速
LinearInterpolator
固定的变化频率
OvershootInterpolator
向前抛出,并超过目标值,然后再返回
TimeInterpolator
实现自定义插值的一个接口
用ValueAnimator来制作动画
ValueAnimator类通过设定动画过程中的int、float或颜色值,来指定动画播放期间的某些类型的动画值。
通过ValueAnimator类的一个工厂方法来获取一个ValueAnimator对象:
ofInt()、ofFloat()、ofObject()。
例如:
ValueAnimatoranimation=ValueAnimator.ofFloat(0f,1f);
animation.setDuration(1000);
animation.start();
在这段代码中,当start()方法开始执行时,ValueAnimator对象会在1000毫秒的动画期间内,在0和1之间开始计算动画的值。
还可以通过下面的做法来指定自定义的动画类型:
ValueAnimatoranimation=ValueAnimator.ofObject(newMyTypeEvaluator(),startPropertyValue,endPropertyValue);
animation.setDuration(1000);
animation.start();
在这段代码中,在start()方法开始执行的时候,ValueAnimator对象会在1000毫秒的动画期间内,使用由MyTypeEvaluator对象提供的逻辑,在startPropertyValue和endPropertyValue之间,开始计算动画的值。
但是,在前一个代码片段中,不会对一个对象形成实际的影响,因为ValueAnimator对象没有直接在对象或属性上执行操作。
这么做的最大可能是用这些计算值来修改那些想要动画效果的对象。
通过定义ValueAnimator类中响应的事件监听器,来处理动画执行期间的重要事件,如帧更新等。
当监听器执行的时候,就能够通过调用getAnimateValue()方法获得指定帧的刷新的计算值。
有关监听器的更多信息,请看“动画监听器”。
用ObjectAnimator来制作动画
ObjectAnimator类是ValueAnimator类的一个子类,并且把时序引擎和ValueAnimator对象的计算值组合到一起,让目标对象的命名属性具备动画能力。
这样使得让任意对象具有动画效果变的更加容易,如不在需要实现ValueAnimator.AnimatorUpdateListener接口,因为被动画的属性会自动的更新。
实例化一个ObjectAnimator对象与实例化一个ValueAnimator对象类似,但是,它还需要跟动画期间的参数一起,指定动画对象和对象动画属性(用一个字符串)的名字:
ObjectAnimatoranim=ObjectAnimator.ofFloat(foo,"alpha",0f,1f);
anim.setDuration(1000);
anim.start();
要正确的更新ObjectAnimator对象的属性,必须做以下事情:
1.动画效果的属性必须有一个set格式的设置器方法。
因为在动画处理期间,ObjectAnimator对象会自动的更新对应的动画效果属性,所以它必须使用这个设置器方法来访问对应的属性。
例如,如果属性名是foo,那么就需要有一个setFoo()方法,如果这个设置器方法不存在,你有三种选择:
A.如果你权利这么做,就要在这个类中添加设置器方法;
B.使用一个你有权改变的包装器类,并且这个包装器能够用一个有效的设置方法来接收动画值,而且还要能够把这个值转发给初始对象。
C.使用ValueAnimator类来代替。
2.如果你只在ObjectAnimator类的一个工厂方法中指定了一个values…参数,那么该值会被假定为动画的结束值。
因此,该对象的动画效果属性就必须要有一个获取方法,用于获得动画的开始值。
这个获取方法必须使用get()格式。
例如,属性是foo,就必须有一个getFoo方法。
3.动画属性的获取(如果需要)和设置方法必须操作相同类型的指定给ObjectAnimator对象开始和结束值。
例如,如果构建一个下面这样的ObjectAnimator对象,就必须要有targetObejct.setPropName(float)和targetObject.getPropName(float)方法:
ObjectAnimator.ofFloat(targetObject,"propName",1f)
4.根据属性或对象上的动画效果,可能需要调用View对象上的invalidate()方法,在更新动画效果时,强制屏幕重绘自己。
在onAnimationUpdate()回调方法中做这件事情。
例如,一个绘图对象的颜色属性的动画效果,在队形重绘自己时,才会将变化结果更新到屏幕上。
在View对象上的所有的属性的设置器,如setAlpha()和setTranslationX()会正确的让View对象失效,因此在调用这些方法设置新的值时候,你不需做失效这件事。
有关监听器的更多信息,请看“动画监听器”。
用AnimatorSet类来编排多个动画
在很多场景中,一个动画的播放要依赖与另一个动画的开始或结束。
Android系统让你把这些相互依赖的动画绑定到一个AnimatorSet对象中,以便能够指定它们是同时的、顺序的、或在指定的延时之后来播放。
AnimatorSet对象也能够彼此嵌套。
以下示例代码来自BouncingBalls示例,它按照以下方式播放Animator对象:
1.播放bounceAnim
2.同时播放squashAnim1、squashAnim2、stretchAnim1和stetchAnim2
3.播放bounceBackAnim
4.播放fadeAnim
AnimatorSetbouncer=newAnimatorSet();
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);
ValueAnimatorfadeAnim=ObjectAnimator.ofFloat(newBall,"alpha",1f,0f);
fadeAnim.setDuration(250);
AnimatorSetanimatorSet=newAnimatorSet();
animatorSet.play(bouncer).before(fadeAnim);
animatorSet.start();
关于如何使用动画集的完整示例,请看APIDemo中的BouncingBalls示例。
动画监听器
使用下列介绍的监听器能够监听动画播放期间的重要事件:
1.Animator.AnimatorListener
onAnimationStart()---动画开始的时候被调用
onAnimationEnd()---动画结束的时候被调用,它不管动画是如何结束的。
onAnimationRepeate()---动画重复播放的时候被调用
onAnimationCancel()---动画被取消播放的时候被调用。
2.ValueAnimator.AnimatorUpdateListener
onAnimationUpdate()---在动画的帧上调用这个方法。
通过监听这个事件,使用在动画期间由ValueAnimator对象产生的计算值。
要使用这个值,就要用getAnimateValue()方法查询传递到事件中的ValueAnimator对象,以便获得当前的动画值。
如果使用ValueAnimator类,那么实现这个监听器是必须的。
根据属性或对象的动画效果,可能需要调用View对象上的invalidate()方法,用新的动画值来强制屏幕的指定区域进行重绘。
例如,Drawable对象的颜色属性的动画效果,在对象重绘自己的时候,只会导致屏幕的更新。
在View对象上的所有属性的设置器,如setAlpha()、setTranslationX()等方法都会正确的让View对象失效,因此在调用这些方法设置新值的时候,你不需要让该View对象失效。
如果不实现Animator.AnimatorListener接口的所有方法,你能够继承AnimatorListenerAdapter类,来代替对Animator.AnimatorListener接口的实现。
AnimatorListenerAdapter类对这些方法提供了空的实现,你可以选择性的重写这些方法。
例如,APIDemo中的BouncingBalls示例就只创建了一个AnimatorListenerdapter类的onAnimationEnd()回调方法:
ValueAnimatorAnimatorfadeAnim=ObjectAnimator.ofFloat(newBall,"alpha",1f,0f);
fadeAnim.setDuration(250);
fadeAnim.addListener(newAnimatorListenerAdapter(){
publicvoidonAnimationEnd(Animatoranimation){
balls.remove(((ObjectAnimator)animation).getTarget());
}
对于ViewGroups对象的动画布局的变化
属性动画系统给ViewGroup对象的动画变化提供了与View对象一样容易动画处理方法。
使用LayoutTransition类在ViewGroup内部处理布局变化的动画。
当调用一个View对象的setVisibility()方法,或者设置该View的GONE常量,或者把该View对象添加到ViewGroup中(或者从ViewGroup中删除)时,在ViewGroup内部的View对象就能够实现时隐时现的动画效果。
当在ViewGroup对象中添加或删除View对象时,其中的其他View对象也能够动画移动到新的位置。
在LayoutTransition对象内通过调用setAnimator()方法,并且在传递给该方法的Animator对象参数中带有下列LayoutTransition常量之一,就能够定义该常量所代表的动画:
1.APPEARING---一个标记,它指示要在容器中正在显示的项目上运行动画;
2.CHANGEAPPEARING---一个标记,它指示在容器中由于新项目的出现而导致其他项目变化所要运行的动画;
3.DISAPPEARING---一个标记,它指示一个从容器中消失的项目所要运行的动画;
4.CHANGE_DISAPPEARING---一个标记,它指示由于一个项目要从容器中消失而导致其他项目的变化,所要运行的动画。
能够给这四种事件类型定义自定义动画,以便定制自己的布局过渡效果,也可以告诉动画系统只使用默认的动画效果。
在APIDemo中的LayoutAnimations示例,显示了如何给布局的过渡定义动画效果,并且在想要动画效果的View对象上设置动画。
LayoutAnimationsByDefault类以及它对应的layout_animations_by_default.xml布局资源文件显示了如何在XML中启用ViewGroup对象的默认布局过渡效果。
需要做的事情仅仅是把ViewGroup元素的android.animateLayoutchanges属性设置为true。
例如:
android:
orientation="vertical"
android:
layout_width="wrap_content"
android:
layout_height="match_parent"
android:
id="@+id/verticalContainer"
android:
animateLayoutChanges="true"/>
如果把这个属性设置为true,那么在该ViewGroup对象中添加或删除View对象,以及ViewGroup对象中其他的View对象都会自动的具有动画效果。
使用TypeEvaluator
如果想要的动画类型是Android系统所未知的,那么通过实现TypeEvaluator接