概览
安卓为UI元素和自己绘制2D、3D图形提供了一系列的API,这篇文章介绍了这些API的主要用法。
动画
安卓框架提供了两种动画系统:属性动画(property animation)和视图动画(view animation)。两种动画效果都可以使用,但是通常情况下推荐使用属性动画(property animation),因为它更灵活并且有更多特性。除了这两种外,你还可以使用帧动画(Drawable animation),这种动画使用图片资源逐帧展示。
属性动画(property animation):
在安卓3.0(API11)引进,属性动画允许你对任何对象的属性进行动画处理,包括未在屏幕上展示的对象。属性动画可以扩展,并且允许你自定义属性。
视图动画(View Animation)
视图动画只能用于views。相对来说它能提供几乎满足你需求的所有动画。
帧动画(Drawable Animation)
帧动画可以逐帧显示图片,就像电影一样。这种动画在你想要显示类似于进度一类的动画时是有用的。
2D和3D图形
在编写应用程序时,重要的是要考虑你的图形需求是什么。不同的图形任务最好用不同的技术来完成。 例如,用于静态应用的图形和动画应当与用于交互式游戏的图形和动画不同地实现。 在这里,我们将讨论在Android上绘制图形的几个选项,以及它们最适合的任务。
画布和图片(Canvas and Drawables)
Android提供了一组View小部件,为各种用户界面提供了一些通用功能。 你还可以扩展这些小部件以修改它们的外观或行为方式。 此外,莫可以使用Canvas类中包含的各种绘制方法来绘制自己的自定义2D渲染,或者为按钮或逐帧动画之类的内容创建Drawable对象。
硬件加速
从安卓3.0引入,允许你是用硬件特性来更好的绘制你的画布。
openGL
Android通过Android框架API以及本地开发工具包(NDK)可以支持支持OpenGL ES 1.0和2.0。当你想要为您的应用程序添加Canvas API不支持的一些图形增强功能时,或者您希望独立于平台并且不要求高性能时,可以使用安卓框架API。与NDK相比,使用框架API有一个性能损失,因此对于许多图形密集型应用程序,如游戏,使用NDK更好(重要的是,你仍然可以使用框架API获得足够的性能。例如,Google Body应用程序完全使用框架API开发)。如果你有很多本地代码,你想移植到Android,使用NDK的OpenGL也是有用的。
属性动画(Property Animation)
属性动画是一个强大的框架,几乎允许你为任何东西做动画。你可以定义随时间更改而改变对象属性的动画,而不用关心它是不是在屏幕上。属性动画在指定的时间内更改属性值。要设置动画,需要指定对象属性,例如对象在屏幕上的位置,设置时间,设置中间值。
属性动画中你可以指定下列特性:
- Duration(过度时间) 定义动画的过渡时间,末日呢是300ms
- Time interpolation 你可以指定计算属性的值作为动画当前已用时间的函数。
- Repeat count and behavior 你可以指定是否在到达持续时间结束时重复动画,以及重复动画的次数。你还可以指定是否要反转播放动画。 将其设置为反向播放动画,然后反复向后播放,直到达到重复次数。
- Animator sets 你可以将多个动画合为一组,包括同时播放、顺序播放或在指定延迟后播放的方式。
- Frame refresh delay 你可以指定刷新频率,默认情况下是每10ms刷新一次,但是程序刷新频率取决于系统的整体忙碌程度。
属性动画是如何工作的
首先让我们来看一个简单的例子:
图1描述了使用其X轴属性的动画对象,表示在屏幕上水平位置的移动。动画的持续时间40ms,行进距离40像素,这样每10ms水平移动10像素。图示的是线性插值动画,速度保持恒定。
你也可以指定非线性插值方式。图2表示的是在动画开始时加速,动画结束时减速的动画过程。仍然是40ms移动40个像素,但是移动过程是非线性的。
图3描述了动画的主要的类的彼此之间的工作
ValueAnimator跟踪当前动画的时间,例如动画运行了多少时间,以及单签的属性值。
ValueAnimator封装了一个定义动画插值器的TimeInterpolator和定义TypeEvaluator。例如在图2中,使用的TimeInterpolator是AccelerateDecelerateInterpolator,使用的TypeEvalutor是IntEvaluator。
要启动动画,请创建ValueAnimator,并为其设置动画属性的起始值和结束值,以及动画的持续时间。 当你调用start()时,动画开始。在整个动画期间,ValueAnimator根据动画的持续时间和已经过去的时间,计算0和1之间的已过比例。 已过比例表示动画已完成的时间百分比,0表示0%,1表示100%。 例如,在图1中,在t = 10ms时的经过比例将是0.25,因为总持续时间是t = 40ms。
当ValueAnimator计算完已经完成的函数后,它调用当前设置的TimeInterpolator来计算接下来的插值函数。 插值函数将经过的函数映射到考虑了设置的时间新插值函数。 例如,在图2中,因为动画缓慢加速,所以插值函数(大约.15)小于经过的函数(.25),在t = 10ms。 在图1中,插值总是与经过的相同。
当计算插值函数时,ValueAnimator调用相应的TypeEvaluator,根据动画的插值函数,起始值和结束值计算你正在进行动画的属性的值。 例如,在图2中,插值函数在t = 10ms时为.15,因此此时的x轴属性值为.15 X(40 - 0)或6。
属性动画如何区别于视图动画
视图动画提供只对view对象进行处理的功能,因此如果你对非view进行动画处理,必须实现自己的代码。视图动画系统也受到约束,因为它仅将View对象的几个属性暴露给动画,例如视图的缩放和旋转,而没有背景颜色。
补间动画可以对View对象的内容执行一系列简单的变换(位置,大小,旋转和透明度)。所以,如果你有一个TextView对象,你可以移动,旋转,增长或收缩文本。 如果它有一个背景图像,背景图像将随文本一起变换。 动画包提供了补间动画中使用的所有类。
视图动画系统的另一个缺点是,它只是在绘制视图时修改,而不是实际的View本身。例如,如果你使一个按钮在屏幕上移动,按钮移动绘制正确,但是你可以点击按钮的实际位置不会改变,所以你必须实现自己的逻辑来处理这个。
使用属性动画,上边提到的视图动画的缺点全都没有,你可以操作视图和非视图对象。属性动画在执行动画方式上也很好,你可以为要制作动画的属性(如颜色,位置或者大小)分配动画制作器,并可以定义动画的各个方面,例如多个动画制作工具的插值和同步。
然而,使用视图动画会比属性动画有较少的设置和代码编写。如果视图动画能满足你现在有的程序,就不需要使用属性动画,也可以结合两者使用。
API概览
Animators
在视图动画中已经定义了很多动画插值器,你也可以在属性动画中使用他们。Animator类为创建动画提供了一个基础框架,正常情况下你不不鞥使用这个类,它只提供了很少的功能,必须要通过继承来扩展它,下面是它的子类:
类 | 描述 |
---|---|
ValueAnimator | 属性动画的主要计时引擎,计算要需要使用动画的属性的值。它具有计算动画值并包含每个动画的时间细节的所有的核心功能,关于动画是否重复执行的信息,接收更新时间的监听器以及设置自定义类型的能力。动画属性有两个部分:计算动画值,设置动画值。ValueAnimator不执行第二部分,因此你必须自己监听有ValueAnimator计算的值的更新,并修改逻辑对象。 |
ObjectAnimator | ValueAnimator的子类,允许您将目标对象和对象属性设置为动画。 此类在为动画计算新值时相应地更新属性。 通常情况下使用ObjectAnimator,因为它使得对目标对象的动画过程更容易。 但是,你有时需要直接使用ValueAnimator,因为ObjectAnimator还有其他一些限制,例如需要在目标对象上存在特定的方法。 |
AnimatorSet | 将一组动画有机的结合起来。你可以设置为同时播放,顺序播放,或者在指定延时后执行动画 |
Evaluators
Evaluators 告诉了属性动画如何根据给定的属性计算值。获取由Animator类提供的时间数据,动画的开始和结束值,并基于这些数据计算属性的值。以下是一些Evaluators:
类/接口 | 描述 |
---|---|
IntEvaluator | 默认的计算int型属性的Evaluator |
FloatEvaluator | 默认的计算float型属性的Evaluator |
ArgbEvaluator | 默认的计算颜色属性(16进制)的Evaluator |
TypeEvaluator | 一个允许你创建自己的Evaluator的接口。如果要对不是int,float或color的对象属性进行动画处理,则必须实现TypeEvaluator接口以指定如何计算对象属性的动画值。如果要处理那些类型与默认行为不同,也可以为int,float和color值指定自定义TypeEvaluator。 |
时间插值器定义动画中的具体值如何对应时间的函数计算。例如,您可以指定动画在整个动画中线性发生,这意味着动画在整个时间内均匀移动,或者您可以指定动画以使用非线性时间,例如,在开始时加速,在结束时减速的动画。表3描述了android.view.animation中包含的内插器。 如果所提供的插值器都不适合您的需要,请实现TimeInterpolator接口并创建自己的插件。
Interpolators
类/接口 | 描述 |
---|---|
AccelerateDecelerateInterpolator | 开始和结束时慢,中间加速的插值器 |
AccelerateInterpolator | 先缓慢后快速的加速器 |
AnticipateInterpolator | 开始正向前然后反向的插值器 |
AnticipateOvershootInterpolator | 先反向在正向超过目标值最后达到目标值 |
BounceInterpolator | 在结束时反弹的插值器 |
CycleInterpolator | 动画重复指定次数的周期插值器 |
DecelerateInterpolator | 快速开始然后减速的插值器 |
LinearInterpolator | 速度恒定的线性插值器 |
OvershootInterpolator | 正向超过目标值然后返回目标值 |
TimeInterpolator | 接口,实现你自己的插值器 |
使用ValueAnimator
ValueAnimator类允许你通过指定一组int,float或颜色设置动画的持续时间,从而为某种类型的值设置动画。 您可以通过调用其工厂方法之一获得一个ValueAnimator:ofInt(),ofFloat()或ofObject()。 例如:
ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f);
animation.setDuration(1000);
animation.start();复制代码
在此代码中,当start()方法运行时,ValueAnimator开始计算动画的值(在0和1之间),持续时间为1000 ms。
您还可以通过执行以下操作,指定自定义动画:
ValueAnimator animation = ValueAnimator.ofObject(new MyTypeEvaluator(), startPropertyValue, endPropertyValue);
animation.setDuration(1000);
animation.start();复制代码
在此代码中,当start()方法运行时,ValueAnimator开始计算startPropertyValue和endPropertyValue之间的动画值,使用由MyTypeEvaluator提供的逻辑,持续时间为1000 ms。
然而,第一段代码片段对对象没有实际影响,因为ValueAnimator不直接对对象或属性操作。 你想做的最可能的事情是修改要用这些计算值的对象。 你可以通过在ValueAnimator中定义监听器以在动画的生命周期内适当地处理重要事件(例如帧更新)来实现此目的。 当实现侦听器时,您可以通过调用getAnimatedValue()获取特定帧刷新的计算值。
使用ObjectAnimator
ObjectAnimator是ValueAnimator的子类,并结合了定时引擎和ValueAnimator的值计算,以及为目标对象的命名属性设置动画的能力。 这使得对任何对象使用动画更容易,因为你不再需要实现ValueAnimator.AnimatorUpdateListener,对象的属性自动更新。
实例化一个ObjectAnimator类似于一个ValueAnimator,但你也指定对象和该对象的属性(作为一个String)的名称以及值之间的动画:
ObjectAnimator anim = ObjectAnimator.ofFloat(foo, "alpha", 0f, 1f);
anim.setDuration(1000);
anim.start();复制代码
要使ObjectAnimator正确的更新属性,必须执行以下操作:
对象的属性必须有set形式的setter函数。因为ObjectAnimator在动画期间自动更新对象的属性,所以必须能够使用setter方法设置属性。例如,属性的名称是foo,则必须有一个setFoo()方法。如果此setter方法不存在,你可以按照下面的方法:
- 可以的情况下将setter方法添加到类中
- 如果你可以更改属性的包装类,可以使包装类接受有效的setter方法,并将其转发到原始对象
- 使用ValueAnimator类
如果你在ObjectAnimator工厂方法中的value的参数仅指定一个值,那么将会假定他是动画的结束值。因此你的对象属性必须要有一个getter方法,用于获取动画的起始值。gettter方法必须是get()形式,例如如果属性的名称是foo,则需要getFoo()方法。你要动画的属性的getter和setter方法必须与你为ObjectAnimator指定的开始值和结束值操作相同的类型。例如,如果构造以下ObjectAnimator,则必须具有targetObject.setPropName(float)和targetObject.getPropName(float):
ObjectAnimator.ofFloat(targetObject,“propName”,1f)复制代码
根据你要动画化的属性或对象,你可能需要在视图上调用invalidate()方法,以强制屏幕使用更新的动画值重绘本身。你可以在onAnimationUpdate()回调中做到这一点。例如,对一个Drawable对象的颜色属性进行动画处理只会在该对象重绘本身时更新屏幕。 View上的所有设置的属性,例如setAlpha()和setTranslationX(),所以当使用新值调用这些方法时,您不需要使invalidate。
下面看几种效果:
1.AccelerateDecelerateInterpolator
效果:动画开始的时候慢速,慢慢加速,后边减速
2.AccelerateInterpolator
效果:动画慢慢加速,最后达到速度最快
3.AnticipateInterpolator
效果:先反向运动一段,然后正向运动
4.AnticipateOvershootInterpolator
效果:先反向运动一小段距离,然后超过终点一段距离,最后回到终点。
5.BounceInterpolator
效果:弹跳效果
6.CycleInterpolator
效果:循环完成多次,在构造器中传入参数,这个参数就是循环的次数,中是例子2次
7.DecelerateInterpolator
效果:速度越来越慢
8.LinearInterpolator
效果:线性匀速运动
9.OvershootInterpolator
效果:超过终点然后返回
使用AnimatorSet编排多个动画
在多数情况下,你想在一个动画开始或者结束的时候启动另一个动画,Android系统允许你将动画捆绑在一起成为AnimatorSet,以便可以指定是同时、按顺序启动动画还是在指定的延迟后启动动画。 您还可以将AnimatorSet对象嵌套在彼此之内。
下面的例子是从Bouncing Balls中提取的一段代码,播放顺序如下:
- 播放bounceAnim。
- 同时播放squashAnim1, squashAnim2, stretchAnim1, 和stretchAnim2。
- 播放bounceBackAnim.
- 播放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();复制代码
下面看两个例子
1.按顺序播放动画
2.按顺序播放动画的同时播放透明度变化
Note:此处注意,在一个set中不能复用同一个动画
动画监听器
你可以在动画执行期间监听一些重要的事件。
Animator.AnimatorListener
- onAnimationStart() 动画启动时调用
- onAnimationEnd() 动画结束时调用
- onAnimationRepeat() 动画重复时调用
onAnimationCancel() 在动画被取消时调用,同时会调用onAnimationEnd(), 无论它是怎样被结束的。
ValueAnimator.AnimatorUpdateListener
- onAnimationUpdate() 每一帧变化都会调用。用户监听此事件以使用动画期间ValueAnimator生成的计算值。 要使用该值,请查询传递到事件的ValueAnimator对象,以使用getAnimatedValue()方法获取当前的动画值。 如果使用ValueAnimator,则需要实现此侦听器。
根据你要动画化的属性或对象,你可能需要在控件上调用invalidate(),以强制屏幕的该区域使用新的动画值重绘本身。 例如,对一个Drawable对象的颜色属性进行动画处理只会在该对象重绘本身时更新屏幕。 View上的所有属性设置,例如setAlpha()和setTranslationX()使Viewinvalidate,所以当使用新值调用这些方法时,您不需要使调用invalidate。
如果不想实现Animator.AnimatorListener接口的所有方法,你可以扩展AnimatorListenerAdapter类,AnimatorListenerAdapter类提供了可以选择覆盖的方法的空实现。
例如,Bouncing Balls例子中创建了一个只有onAnimationEnd回掉方法的AnimatorListenerAdapter。
ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
fadeAnim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
balls.remove(((ObjectAnimator)animation).getTarget());
}复制代码
动画对ViewGroup的布局更改
属性动画系统能够为ViewGroup对象提供像对View对象一样简单的方法来制作动画。
你可以使用LayoutTransition类在一个ViewGroup种使用动画来更改布局。当你为添加和删除的动作添加动画时,使用android.view.View.GONE,VISIBLE,INVISIBLE等或者调用set Visibility()方法设置可见不可见的时候,你可以调用setAnimator()并传入具有以下LayoutTransition常量的Animator对象,在LayoutTransiton种定义动画:
- APPEARING - 一个在容器中添加item时候的动画的标记
- CHANGE_APPEARING - 一个在容器中由于添加新的item而引起其他条目变化的动画标记
- DISAPPEARING -一个在容器中消失的动画的标
- CHANGE_DISAPPEARING - 一个由于某个item消失而引起的其他item变化的动画
API演示中的LayoutAnimations示例显示了如何定义布局转换的动画,然后在要设置动画的View对象上设置动画。
LayoutAnimationsByDefault及其相应的layout_animations_by_default.xml布局资源文件显示如何在XML中为ViewGroups启用默认布局转换。 你唯一需要做的是为ViewGroup设置android:animateLayoutchanges属性为true。 例如:
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="@+id/verticalContainer"
android:animateLayoutChanges="true" />复制代码
将此属性设置为true会自动为从ViewGroup中添加或删除的视图以及ViewGroup中的其余视图创建动画。
使用TypeEvaluator
如果要为Android系统未知的类型设置动画,可以通过实现TypeEvaluator接口创建自己的evaluator 。 Android系统已知的类型是int,float或color,它们由IntEvaluator,FloatEvaluator和ArgbEvaluator类型evaluator 支持。
在TypeEvaluator接口中只有一种方法,即evaluate()方法。这允许你使用的animator在动画的当前点为动画属性返回适当的值。 FloatEvaluator类演示如何做到这一点:
public class FloatEvaluator implements TypeEvaluator {
public Object evaluate(float fraction, Object startValue, Object endValue) {
float startFloat = ((Number) startValue).floatValue();
return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);
}
}复制代码
Note:当ValueAnimator(或ObjectAnimator)运行时,它计算动画的当前已过比例(0到1之间的值),然后根据你使用的插值器器计算插值号。 插值函数是你的TypeEvaluator通过fraction参数接收的,所以你不必在计算动画值时考虑插值器。
使用Interpolators
插值器定义动画中的具体值与时间的函数关系。例如你可以指定动画在整个动画期间内线性运动,你也可以使用非线性运动,加速和减速运动。
动画系统中的插值器从动画制作器接收表示动画的经过时间的函数。 插值器修依靠函数以与其目标提供的动画类型一致。 Android系统在android.view.animation包中提供了一组常见的内插器。 如果这些都不符合你的需要,你可以实现TimeInterpolator接口并创建自己的插值器。
作为示例,下面比较默认内插器中的AccelerateDecelerateInterpolator和LinearInterpolator如何计算插值函数。 LinearInterpolator对已过的没有影响。 AccelerateDecelerateInterpolator加速然后减速。
AccelerateDecelerateInterpolator
public float getInterpolation(float input) {
return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}复制代码
LinearInterpolator对已过的没有影响
public float getInterpolation(float input) {
return input;
}复制代码
下面的表中列出了插值器在持续1000ms的过程种对应的数值:
时间 | Linear函数值 | Accelerate/Decelerate函数值 | |
---|---|---|---|
0 | 0 | 0 | |
200 | .2 | .1 | |
400 | .4 | .345 | |
600 | .6 | .8 | |
800 | .8 | .9 | |
1000 | 1 | 1 |
上表中可以看到,Linear是匀速运动,每200ms移动0.2。AccelerateDecelerateInterpolator是变速运动,200-600ms时加速很快,600-1000ms时变化慢。
定义关键帧
关键帧对象由时间/值的键值对组成,允许您在动画的特定时间定义特定状态。每个关键帧也可以有自己的插值器,以控制动画在前一个关键帧的时间和该关键帧的时间之间的间隔中的行为。
要实例化一个Keyframe对象,必须使用ofInt(),ofFloat()或ofObject()的工厂方法之一来获取相应类型的关键帧。然后调用ofKeyframe()工厂方法来获取PropertyValuesHolder对象。 一旦你有了对象,你可以通过传入PropertyValuesHolder对象和对象来获得animator。 以下代码段演示了如何执行此操作:
Keyframe kf0 = Keyframe.ofFloat(0f, 0f);
Keyframe kf1 = Keyframe.ofFloat(.5f, 360f);
Keyframe kf2 = Keyframe.ofFloat(1f, 0f);
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2);
ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation)
rotationAnim.setDuration(5000ms);复制代码
控件动画
属性动画系统允许对View对象使用流线型动画,并且提供了超过视图动画系统的一些优点。 视图动画系统通过更改绘制对象的方式来转换视图对象。 这是在每个View的容器中处理的,因为View本身没有可操作的属性。 这导致View被动画化,但是View对象本身没有改变。 这导致对象,即使它被绘制在屏幕上的不同位置,仍然存在于其原始位置。在Android 3.0中,添加了新的属性和相应的getter和setter方法以消除此缺点。
属性动画系统可以通过更改View对象中的实际属性来在屏幕上更新View。 此外,View还会在其属性更改时自动调用invalidate()方法来刷新屏幕。 的View类中的新属性是:
- translationX & translationY: 这些属性控制视图作为从其布局容器设置的左侧和顶部坐标的增量的位置。
- rotation & rotationX & rotationY: 这些属性控制2D(旋转属性)中的旋转和围绕中心点3D的旋转。
- scaleX and scaleY: 2D上控制缩放
- pivotX and pivotY: 控制中心点的位置,围绕该点旋转和缩放变换。 默认情况下,该点位于对象的中心。
- x and y: 用于在其容器中描述视图的最终位置,作为左侧值和顶部值以及translationX和translationY值的总和。
- alpha: 描述View的透明度,0表示全透明,1表示不透明。
为了使View对象的属性拥有动画,例如他的颜色或者旋转角度,你要做的就是创建一个property animator对象并且指定你想要动画的属性。
ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f);复制代码
ViewPropertyAnimator动画
使用ViewPropertyAnimator进行动画处理。ViewPropertyAnimator提供了一种简单的方法来使用单个底层Animator对象来并行地对视图的多个属性进行动画。 它的行为非常像一个ObjectAnimator,因为它修改View的属性的实际值,但是当同时对许多属性更有效。 此外,使用ViewPropertyAnimator的代码更简洁,更容易阅读。 以下代码片段显示了在同时对视图的x和y属性进行动画处理时,在使用多个ObjectAnimator对象,单个ObjectAnimator和ViewPropertyAnimator时的差异。
多个动画
ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();复制代码
单个动画
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();复制代码
ViewPropertyAnimator
myView.animate().x(50f).y(100f);复制代码
在xml文件种声明动画
属性动画系统允许您使用XML声明属性动画,而不是以编程方式。 通过在XML中定义动画,您可以轻松地在多个活动中重复使用动画,并更轻松地编辑动画序列。
要将使用新属性动画API的动画文件与使用旧视图动画框架的动画文件区分开来,从Android 3.1开始,您应该将属性动画的XML文件保存在res / animator /目录中。
以下属性动画类具有以下XML标记的XML声明支持:
- ValueAnimator -
- ObjectAnimator -
- AnimatorSet -
下面的例子是顺序播放两个动画,第一个动画集合中的两个动画是同时播放的:
<set android: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>复制代码
为了运行此动画,您必须将代码中的XML资源扩充为AnimatorSet对象,然后在开始动画集合之前为所有动画设置目标对象。 为方便起见,调用setTarget()为AnimatorSet的所有子项设置单个目标对象。 以下代码显示了如何执行此操作:
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
R.anim.property_animator);
set.setTarget(myObject);
set.start();复制代码
最后附上github地址:
Demo