Property Animation(属性动画)
2016-07-12 10:06
176 查看
概述
属性动画系统是一个强大的框架,它允许你将大多数东西动画化。你可以定义一个动画用来在动画播放的时候改变任何对象的属性值,而不管它在屏幕上有没有被绘制。属性动画在指定长度的时间内改变一个属性(对象的一个字段)的值。开始动画化一些东西,由你指定你想要动画化的对象属性,如一个在屏幕上的对象的属性,指定动画播放的时长,和在动画时改变成什么值。属性动画系统会指导你如何去定义一个动画,只需要遵循如下步骤:
持续时间:可以指定动画的持续时间,默认是300ms
时间插值:可以在动画运行时通过一个函数来指定需要改变的属性值多久计算一次。
重复次数和行为:当动画播放到末尾时,可以指定是否重复播放以及播放的次数。你还可以指定动画是否倒着播放。设置反向播放动画反复向前然后向后,直到达到重复出现的次数。
动画设置:可以对动画进行逻辑分组,一起播放或顺序播放或指定延迟播放。
帧刷新延迟:可以指定动画帧的刷新频率。默认值是每10ms刷新一次,但是最终的刷新速度取决于你系统整体的繁忙度和响应时间。
属性动画工作原理
首先,让我们通过一个简单的例子来了解动画是如何工作的。图1描述了一个假设的对象对它的x属性进行动画化,即它在屏幕上的水平位置。动画的持续时间设置为40ms并且x增大了40像素。每10ms,即默认帧刷新时间,该对象的水平距离就移动10像素。到最后的40ms时,动画停止,此时该对象的水平距离是40。这就是一个带有线性插值的动画,意味着该对象以一个恒定速度移动了。图1.线性动画示例
你也可以将它设置为非线性的。图2说明了一个假想的对象在动画的前一段时间内加速,后一段时间内减速的动画效果。该对象依旧是在40ms中移动了40像素,但并非线性的。开始的一段时间,该动画加速至一半的点(即X=20),然后从这点开始减速,直到最后。如图2所示,开始和结束时移动的距离小于中间。
图2.非线性动画示例
让我们详细的看看属性动画系统的重要组件是如何像上面一样计算动画的。图3描述了主要的类是如何与其他类工作的。
图3.动画是如何计算的
对象在动画期间持续跟踪,如动画已经运行了多长时间,和当前动画的属性值。ValueAnimator
封装了一个ValueAnimator
,被用来定义动画开始后的属性值。例如,在图2,TypeEvaluator
将会使用TimeInterpolator
,而AccelerateDecelerateInterpolator
将会使用TypeEvaluator
.。IntEvaluator
开始一个动画,创建一个
ValueAnimator
并且给它你想要动画化属性开始和结束的值,随着动画的进行。当调用
计算一个在0和1之间的已播放分数(elapsedValueAnimator
fraction),基于持续时间和已播放时间。这个已播放分数代表着动画播放完成时间的百分百,0意味着0%,1意味着100%。例如,在图1,在t=10ms时的已播放分数是0.25因为总的持续时间是40ms。
当
计算完成了一个已播放分数,就会调用刚才设置的ValueAnimator
来计算插值分数(interpolatedTimeInterpolator
fraction)。一个插值分数将已播放分数映射到一个新的需要考虑时间插值的分数。例如,图2中,因为动画是逐渐加速的,在t=10ms时,它的插值分数,大约是0.15,小于此时的已播放分数0.15。在图1,插值分数永远等于已播放分数。
当插值分数计算完成,
调用适当的ValueAnimator
,来计算你需要动画化的属性的值,基于插值分数,开始值和结束值。例如,在图2中,tTypeEvaluator
=10ms时的插值分数是0.15,所以此时的属性值将会是0.15x(40-0),或者6。
在
com.example.android.apis.animation包下的API
Demos有许多关于如何使用属性动画系统的例子。
属性动画与视图动画的不同之处
视图动画系统仅仅提供了动画化view对象的能力,因此如果你想要动画化非view对象,只能由你自己去编码实现了。视图动画系统也是受限制的,因为它只公开了几个方面的动画视图对象,如对view的缩放和旋转,而没有背景颜色。视图动画的另一个缺点是它只在View绘制时修改视图,并非真正修改view本身。例如,如果你实现一个让一个按钮从左至右穿过屏幕这样的一个动画,按钮会正确的绘制,但是它的实际位置是没有变化的,你还是可以在原来的位置点击它,所有你必须实现自己的逻辑来处理这个问题。
而属性动画系统,这些约束完全被移除了,并且你可以动画化任何对象(view和非view)的任何属性,对象本身也确实被修改了。属性动画系统也用更健壮的方式执行动画。在更高层次上,你可以为你想要动画化的属性,如颜色,位置,或大小,分配动画师,并且可以定义动画的各个方面,如插值和多个画师同步。
视图动画系统,然而,花费更少的时间来设置,需要更少的代码编写。如果视图动画完成了你需要做的一切,或者如果你现有的代码已经按你所期望的方式工作了,那就不需要使用属性动画系统了。如果用例出现了不同的情况,使用动画系统也是十分有意义的。
API概述
在.中可以找到最多的关于属性动画系统的API相关知识。因为在android.animation
中已经定义了许多视图动画系统的插入器,你可以在属性动画系统中使用这些插入器。接下来的几张表格展示了属性动画系统的主要组件。android.view.animation
Table1.Animators
Class | Description |
---|---|
| 属性动画的主要计时引擎,也经常计算动画时的属性值。它具有所有的核心功能——计算动画值和包含每个动画的时间细节,有关于动画何时重复播放的信息,接收更新事件的监听器,设置自定义的估计(evaluate)类型.它主要有两个功能:计算动画的值和在动画时为对象设置这些值。并不执行第二个功能, 因此你必须通过监听. 计算出来的值的更新事件 来用你自己的逻辑修改你想要动画的对象的值。查看 |
| 的一个子类,允许你设置目标对象和需要动画化的属性。 该类根据动画计算出来的新值来更新属性值.大多数时候你需要用到 , 因为它使动画值用在目标对象上更加容易。然而,有些时候你必须直接使用 因为 有一些限制,例如在目标对象上请求特定的存取方法。 |
| 提供一个组织动画的途径,这样你可以让它们通过一个顺序运行。例如一起播放,顺序播放,或延迟播放.查看 |
类来获取提供的时间数据,动画开始和结束的值,并且基于这些值计算动画时的属性值。属性动画系统支持如下求值器:Animator
Table2.Evaluators
Class/Interface | Description |
---|---|
| 计算int属性的默认求值器 |
| 计算float属性的默认求值器 |
| 计算颜色属性的默认求值器,是一个十六进制的值 |
| 一个允许你创建自己的求值器的接口。如果你要计算的对象属性值不在int,float,或颜色之中,你必须实现接口来指定如何计算动画属性值。你也可以为int,float,color指定一个自定义的求值器,如果不你想用默认方法的处理这些类型。查看 |
.中的插值器。如果这之中没有你需要的,实现android.view.animation
Table3.Interpolators
Class/Interface | Description |
---|---|
| 开始和结束时慢,中间快 |
| 开始慢,然后加速 |
| 开始向后,然后向前 |
| 开始向后,甩向前并且冲过目标值,最终回到目标值 |
| 最后反弹 |
| 重复指定次数 |
| 开始快,然后减速 |
| 恒定不变速度 |
| 甩向前,冲过目标值,然后回来 |
| 可以让你实现自动的插值器的一个接口 |
使用ValueAnimator制作动画
类可以在动画持续时间内通过指定一组int,floatValueAnimator
或color值实现某些动画类型。通过调用它的工厂方法来获得
:ValueAnimator
,ofInt()
,ofFloat()
or
例如ofObject()
ValueAnimatoranimation=ValueAnimator.ofFloat(0f,1f);
animation.setDuration(1000);
animation.start();[/code]
代码中,当
start()方法开始运行时,
开始计算动画值,介于0和1之间,持续时间是1000msValueAnimator
。
你还可以为动画指定一个自定义类型,如下:
ValueAnimatoranimation=ValueAnimator.ofObject(newMyTypeEvaluator(),startPropertyValue,endPropertyValue);
animation.setDuration(1000);
animation.start();[/code]
代码中,当start()方法开始运行时,
开始计算动画值,介于ValueAnimator
startPropertyValue和
endPropertyValue之间,使用由
MyTypeEvaluator提供的逻辑,持续时间1000ms
。
上面的代码片段,是的,在一些对象上是没有有实际作用的,因为
并不直接操作对象或值。更有可能的方法是通过修改这些动画的计算值来修改对象。在ValueAnimator
中定义一个监听器来处理动画期间的重要事件,如帧刷新。当实现了该监听器,你可以通过调用ValueAnimator
.得到这一帧刷新时的计算值。更多关于这个监听器的知识,请看getAnimatedValue()
使用ObjectAnimator制作动画
是ObjectAnimator
的子类(在之前章节介绍过)并且结合了时序引擎和计算ValueAnimator
因为它的动画属性会自动更新。ValueAnimator.AnimatorUpdateListener,
实例化一个
对象和实例化ObjectAnimator
)和两个动画值:
ObjectAnimatoranim=ObjectAnimator.ofFloat(foo,"alpha",0f,1f);
anim.setDuration(1000);
anim.start();[/code]
为了让
正确的更新,你必须做如下工作:ObjectAnimator
○需要动画的对象属性必须要有函数形式为set<propertyName>()的setter函数。因为
在动画时自动的更新属性,一定要通过这个setter函数来设置属性。例如,如果这个属性名为ObjectAnimator
foo,你就必须要有一个setFoo()的方法。如果没有这样的setter
方法,你有三种选择:
如果你有权利这么做,在类中加入这个setter方法。
使用包装类,这样你就有权去更改这个包装类,并且该包装类通过setter函数获得有效的值,并将它转发给原来的对象。
使用
替代ValueAnimator
○如果在
的某一构造函数中,你的ObjectAnimator
values...参数中只有一个值,它将被假定为结束值。因此,动画对象的属性必须有一个getter函数用来获得动画开始时的开始值。这个getter函数必须是get<propertyName>()形式的。例如,如果属性名为foo,你必须有一个getFoo()的函数。
○动画属性的getter
函数(如果需要)和setter函数必须操作的是同一类型的由
指定的开始和结束值。例如,如果你构造了如下的ObjectAnimator
:,你必须有ObjectAnimator
targetObject.setPropName(float)和
targetObject.getPropName(float):
ObjectAnimator.ofFloat(targetObject,"propName",1f)[/code]
取决于你的动画属性和对象,当view显示在屏幕上时,你或许需要调用
上的设置,如
和setAlpha()
直接无效了,所以当调用这些方法设置新值时,你不必无效化view。更多关于监听器的信息,请查看setTranslationX()
使用AnimatorSet编排复合动画
在许多情况下,你想要播放的动画取决于其它的动画开始或结束后。安卓系统使你可以在)
对象。AnimatorSet
接下来的示例代码取自Bouncing
Balls示例(简单的修改了)通过如下的方式播放了如下的
对象:Animator
Plays
bounceAnim.
Plays
squashAnim1,
squashAnim2,
stretchAnim1,
and
stretchAnim2同时播放
Plays
bounceBackAnim.
Plays
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();[/code]
更多关于如何使用动画集合的完整示例,请看API示例中的Bouncing
Balls实例。
动画监听器
在动画持续时间内,你可以监听如下重要的事件。Animator.AnimatorListener
-onAnimationStart()
动画开始是调用
-onAnimationEnd()
动画结束时调用
-onAnimationRepeat()
动画重复播放时调用
-onAnimationCancel()
动画取消时调用.取消动画也会调用
,onAnimationEnd()
无论该动画是否已经播放完成。
ValueAnimator.AnimatorUpdateListener
-onAnimationUpdate()
动画的每一帧时调用.在动画期间,通过监听该事件来使用由
对象,通过ValueAnimator
来获取当前动画值。如果你使用了getAnimatedValue()
就需要实现这一监听器。ValueAnimator
取决于你的动画属性和对象,当view显示在屏幕上时,你或许需要调用invalidate()方法来重绘视图和更新动画值。在onAnimationUpdate()回调函数中做这些事情。例如,为一个可绘制对象的颜色属性做动画,当这个对象重绘自己的时候才导致更新屏幕。所有view上的设置,如setAlpha()和setTranslationX()直接无效了,所以当调用这些方法设置新值时,你不必无效化view。
你可以继承
类而不是实现AnimatorListenerAdapter
类提供了空的实现方法供你选择性的覆盖。AnimatorListenerAdapter
例如,在api示例中的
:onAnimationEnd()
ValueAnimatorAnimatorfadeAnim=ObjectAnimator.ofFloat(newBall,"alpha",1f,0f);
fadeAnim.setDuration(250);
fadeAnim.addListener(newAnimatorListenerAdapter(){
publicvoidonAnimationEnd(Animatoranimation){
balls.remove(((ObjectAnimator)animation).getTarget());
}[/code]
为ViewGroups做布局改变动画
属性动画系统提供了对ViewGroup对象动画化的能力,使得像动画化View一样简单。通过使用
方法设置时。当你添加或移除View时,ViewGroup中其余的View也可以动画移动到新的位置。通过调用setVisibility()
的LayoutTransition
传递一个setAnimator()
对象和如下的一个Animator
常量,来定义一个动画:LayoutTransition
APPEARING-一个标志,表明那些出现在容器中的项目的动画。
CHANGE_APPEARING-表明那些由于新项目出现在容器中而需要改变的项目的动画
DISAPPEARING-表明那些从容器中消失的项目的动画
CHANGE_DISAPPEARING-表明那些由于一个项目在容器中消失而需要改变的项目的动画,
你可以定义你自己的动画效果,由这四个类型的事件来定制你的布局过渡效果,或者直接告诉动画系统使用默认动画。
在api样例中的
android:animateLayoutchanges属性为
true,如下:
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="@+id/verticalContainer"
android:animateLayoutChanges="true"/>[/code]
设置这个属性为真,会自动的动画视图,当从这个ViewGroup中添加或移除视图时。添加/移除的项和剩下的项都有动画效果。
使用TypeEvaluator
如果你想要动画化的类型在安卓系统中未知,你可以通过实现接口来创建自己的求值器。目前安卓系统可识别的类型是int,floatTypeEvaluator
或一个颜色值,分别对应
,IntEvaluator
,FloatEvaluator
和
的类型求值器。ArgbEvaluator
在
接口中只有一个需要实现的方法,TypeEvaluator
在动画的确切时间点返回的适当的动画属性值。
类演示了如何做:FloatEvaluator
publicclassFloatEvaluatorimplementsTypeEvaluator{
publicObjectevaluate(floatfraction,ObjectstartValue,ObjectendValue){
floatstartFloat=((Number)startValue).floatValue();
returnstartFloat+fraction*(((Number)endValue).floatValue()-startFloat);
}
}[/code]
注:当
(orValueAnimator
)运行时,为动画计算了一个确切的已运行分数(介于0-1之间的值),然后计算了一个插值,具体取决于你所使用的插值器。插值分数是你的ObjectAnimator
fraction参数收到的,所有在计算动画值时不需要考虑插值器。
使用插值(Interpolators)
一个插值定义了如何在动画时计算具体值的一个时间函数。例如,你可以指定动画在播放时是线性的,意味着动画在整个播放时间内是匀速运动的,或者可以指定为非线性的,例如在开始时加速,结束时减速。动画系统中的插值器接收一个由动画师发来的分数,这个分数代表着动画已经播放的时间。插值器修改这个分数用以与提供的目标动画类型相一致。在
android.view.animation package.包下安卓系统提供了一组通用的插值器。如果这些都不适合你,可以实现
接口来创建自己的插值器。TimeInterpolator
举个例子,比较默认的插值器
和AccelerateDecelerateInterpolator
是如何计算插值分数的。LinearInterpolator
对已播放分数没有影响。LinearInterpolator
AccelerateDecelerateInterpolator
publicfloatgetInterpolation(floatinput){
return(float)(Math.cos((input+1)*Math.PI)/2.0f)+0.5f;
}[/code]
LinearInterpolator
publicfloatgetInterpolation(floatinput){
returninput;
}[/code]
下表展示了由这些插值器计算一个时长为1000ms的动画的近似值:
已播放 ms | 已播放分数/插值分数 (Linear) | 插值分数 (Accelerate/Decelerate) |
---|---|---|
0 | 0 | 0 |
200 | .2 | .1 |
400 | .4 | .345 |
600 | .6 | .8 |
800 | .8 | .9 |
1000 | 1 | 1 |
以恒定速度改变值,每过200ms增长.2。LinearInterpolator
比AccelerateDecelerateInterpolator
改变值的速度,在200msLinearInterpolator
-600ms的时候更快,在600ms-1000ms的时候更慢。
指定关键帧
关键帧对象由一个时间/值对组成,是由你指定的动画中的一个特定时间的状态。每一个关键帧都有自己的插值器来控制他们的动画行为,在前一个关键帧和这一个关键帧之间。实例化一个
对象,你必须yonder其中的一个工厂方法,Keyframe
,ofInt()
,ofFloat()
或
来获得合适类型的ofObject()
Keyframe。之后调用
工厂方法来获得一个ofKeyframe()
对象。一旦你有了该对象,你可以通过传递PropertyValuesHolder
该对象和目标动画对象来获得一个动画制作者对象。像这样:
Keyframekf0=Keyframe.ofFloat(0f,0f);
Keyframekf1=Keyframe.ofFloat(.5f,360f);
Keyframekf2=Keyframe.ofFloat(1f,0f);
PropertyValuesHolderpvhRotation=PropertyValuesHolder.ofKeyframe("rotation",kf0,kf1,kf2);
ObjectAnimatorrotationAnim=ObjectAnimator.ofPropertyValuesHolder(target,pvhRotation)
rotationAnim.setDuration(5000ms);[/code]
更多关于如何使用关键帧的完整示例,请看API案例中的
视图动画化
属性动画系统允许查看对象的流线型动画,并且在视图动画系统上提供了一些优势。视图动画系统通过改变它绘制的方式来变换view对象。由各个view容器处理,因为view本身没有属性可用来操作。这导致view可以被动画化,但是view本身不会有变化。这样就会有一个对象仍然在原来的位置的现象,尽管它被绘制在了屏幕的不同位置。在安卓3.0,新的属性和相应的getter&setter方法被加入了,用以消除这一弊端。
属性动画系统可以通过改变view对象的实际值而在屏幕上动画化view。另外,当它的属性被改变时,views经常自动的调用
方法来刷新屏幕。在Viewinvalidate()
类中新添加的属性如下:
translationXand
translationY:
这些属性控制了View的位置,作为它左部和上部坐标的增量,由布局容器设置。平移
rotation,
rotationX,
and
rotationY:这些属性控制了在2D和3D坐标系中围绕着中心点(锚点)的旋转。旋转
scaleXand
scaleY:这些属性控制了在2d坐标系中围绕着中心点(锚点)的缩放。缩放
pivotXand
pivotY:
这些属性控制了中心点的位置,它与旋转和缩放转换有关。默认情况下,中心点位于对象的正中央。锚点
xand
y:
用来描述view在容器中的最终坐标,是左部和上部加上x和y的偏移量的和。
alpha:代表着view的透明度变化。默认值为1(不透明),越接近0代表着越透明(看不见)。
动画化一个view对象的属性,如它的颜色或旋转值,你只需要做的就是创建一个属性动画师,并且指定你想要动画化的属性。如:
ObjectAnimator.ofFloat(myView,"rotation",0f,360f);[/code]
更多关于如何创建动画师的信息,看上文的
使用ViewPropertyAnimator制作动画
提供了一个简单的方法来并行动画化几个视图属性,使用一个简单的底层ViewPropertyAnimator
对象。它的行为更像是Animator
,因为它修改了view的真实属性值,但是更加高效的是它同时动画化许多属性。另外,关于使用ObjectAnimator
,和ObjectAnimator
在同时动画化x和y属性时的不同。ViewPropertyAnimator
MultipleObjectAnimatorobjects
ObjectAnimatoranimX=ObjectAnimator.ofFloat(myView,"x",50f);
ObjectAnimatoranimY=ObjectAnimator.ofFloat(myView,"y",100f);
AnimatorSetanimSetXY=newAnimatorSet();
animSetXY.playTogether(animX,animY);
animSetXY.start();[/code]
OneObjectAnimator
PropertyValuesHolderpvhX=PropertyValuesHolder.ofFloat("x",50f);
PropertyValuesHolderpvhY=PropertyValuesHolder.ofFloat("y",100f);
ObjectAnimator.ofPropertyValuesHolder(myView,pvhX,pvyY).start();[/code]
ViewPropertyAnimator
myView.animate().x(50f).y(100f);[/code]
更多关于
,的详细信息,请看相应的安卓开发博文blogViewPropertyAnimator
post.
在XML文件中声明动画
属性动画系统允许你在xml文件中什么属性动画,代替编程实现。在xml中定义你的动画,可以更加方便的复用你的动画且更加容易的对动画排序。为了区分动画文件,使用了那些使用传统视图动画框架的新的属性动画API,始于安卓3.1,你可以在
res/animator/目录(不是res/anim/)下保持你的属性动画xml文件。使用animator目录是可选的,但是如果你想使用ADT插件(ADT
11.0.0+)的视图编辑工具时,这是必须的。因为ADT只会查找在res/animator/目录下的属性动画文件。
下面是属性动画类对应的xml标签元素:
-ValueAnimator
<animator>
-ObjectAnimator
<objectAnimator>
-AnimatorSet
<set>
following下面一个案例播放了两套顺序播放的动画对象,第一个对象通过嵌套设置两个动画对象一起播放:
<setandroid:ordering="sequentially">
<set>
<objectAnimator
android:propertyName="x"
android:duration="500"
android:valueTo="400"
android:valueType="intType"/>
<objectAnimator
android:propertyName="y"
android:duration="500"
android:valueTo="300"
android:valueType="intType"/>
</set>
<objectAnimator
android:propertyName="alpha"
android:duration="500"
android:valueTo="1f"/>
</set>[/code]
运行这个动画,你必须在你代码的
来设置一个简单对象,为方便,目标会应用于所有setTarget()
AnimatorSetset=(AnimatorSet)AnimatorInflater.loadAnimator(myContext,
R.anim.property_animator);
set.setTarget(myObject);
set.start();[/code]
更多关于xml语法定义属性动画的信息,请看Animation
Resources.
相关文章推荐
- php结合安卓客户端实现查询交互实例
- 安卓输入框被虚拟键盘挡住的问题(微信开发)
- Android安卓中循环录像并检测内存卡容量
- Eclipse导出安卓apk文件的图文教程
- 在安卓系统中插入表情到光标位置的代码详解
- Almp 安卓系统上搭建本地php服务器环境的步骤
- Android中编写属性动画PropertyAnimation的进阶实例
- 谷歌被屏蔽后如何搭建安卓环境
- 图文详解Android属性动画
- 安卓APP测试之使用Burp Suite实现HTTPS抓包方法
- 安卓(Android)聊天机器人实现代码分享
- 安卓(android)怎么实现下拉刷新
- Android中Fragment的生命周期与返回栈的管理
- Android中Property Animation属性动画编写的实例教程
- 分享一个安卓的内置多种工具类的Activity
- 安卓系统中实现摇一摇画面振动效果的方法
- java实现获取安卓设备里已安装的软件包
- 安卓(Android)中如何实现滑动导航