第1章 属性动画及动画与图形概述
Android提供了一系列强大的API来把动画加到UI元素中,以及绘制自定义的2D和3D图像中去。下面的几节将综述这些可用的API以及系统的功能,同时帮你做出最优的选择
1.1 动画
Android框架提供了两种动画系统:属性动画(在Android3.0中加入)以及View动画。这两种动画系统都有可行的选择,但是总的来说,属性动画系统是更好的选择,因为它更加灵活,并提供了更多的特性。在这两种系统之外,你可以使用Drawable动画(帧动画),就是你可以加载画图资源,并一帧接一帧的显示它们。
属性动画:
在Android3.0中加入 (API level 11), 属性动画系统可以使任何对象的属性成为动画,包括那些不会在屏幕上显示的对象。这个系统是可扩展的,而且也适用于自定义类型。
View动画:
View动画则是比较旧的系统,只能用于View类。它相对属性动画来说更容易设置,而且足够满足许多应用的需求。
Drawable动画:
Drawable动画即一个接一个的显示Drawable资源,就像放一部电影。如果你想要的动画可以简单的用资源来表示,比如一系列的位图,那就可以用这种方法
1.2 2D和3D图形
当你写一个应用时,首先确定你的图形需求十分的重要,不同的图形任务最好用不同的技术来实现。举例来说,一个稳定的应用软件和一个互动性比较多的游戏相比,它们的图形和动画是有很大不同的。在这里,我们要讨论在Android上绘图的一些方式,以及它们分别适用于哪些任务。
Canvas和Drawables:
Android 提供了一系列的View控件来为大量的用户界面提供常规的支持。你也可以继承这些控件来修改它们的外表或行为方式。除此以外,你可以你可以用Canvas类里的各种绘图方法自定义2D渲染,或创建如帧动画那样的Drawable对象。
硬件加速:
从Android 3.0开始, 你可以通过Canvas API来硬件加速大多数的绘画工作,从而进一步提高它们的性能。
OpenGL:
Android 在框架API层面和NDK上都支持 OpenGL ES 1.0 和 2.0。当你想加入少数一些Canvas API不支持的图像增强时,或是你希望平*立,而不需要高性能时,你可以使用框架API。相比框架API,使用NDK时,性能会有明显的突破,所以对于许多关注图形的应用,比如游戏,使用NDK是更有利的选择。如果你有很多的本地代码想转到Android平台上,也可以使用NDK上的OpenGL。
1.3 属性动画
属性动画系统是一个强大的框架,它允许你让几乎所有的东西变成动画。无论是否它绘制到屏幕上或没有,伴随时间的推移,你可以定义一个动画改变任何对象的属性。在指定的时间长度内,属性动画改变了属性(对象的一个域)的值。对应某些动画内容,如指定你想要某个对象的属性变成动画,例如一个对象在屏幕中的位置,动画的时间,动画之间的值,它都可以搞定。
属性动画系统可让你定义以下特性的动画:
◆Duration(时间):你可以指定动画的持续时间。默认长度是300毫秒。
◆Time interpolation(时间加速器):定义了动画变化的频率。
◆Repeat count and behavior(重复计数和行为):您可以指定是否有一个动画的重复,当它到达时间结束,如何多次重复的动画。您还可以指定是否要反向播放动画。把它设置为reverse动画向前然后向后反复,直到重复次数达到。
◆Animator sets(动画设置):你能按照一定的逻辑设置来组织动画,一起播放或顺序播放或指定延迟后播放。
◆Frame refresh delay(帧刷新延迟):您可以指定多长时间一次刷新你的动画帧。默认设置每10毫秒刷新,但在你的应用程序可以指定刷新帧的速度,最终取决于系统整体的状态和依据底层的定时器提供多快的速度。
1.4 属性动画如何工作
首先,让我们去如何动画一个简单的例子。图1-1描绘了一个假想的动画对象的x属性,代表其在屏幕上的水平位置。动画的持续时间设置为40毫秒和旅行的距离是40像素。每隔10毫秒,这是默认的帧刷新速率,物体水平移动10个像素。在40ms的结束,动画停止,对象在水平位置40结束。这是一个线性插值动画的例子,这意味着对象在一个恒定的速度移动。
图1-1 一个线性动画的例子
你还可以指定动画有一个非线性加速器。图1-2说明了一个假想的对象,在开头动画加速,在动画结束时减速。对象仍然在40毫秒移动40个像素,但非线性。在开始的时候,这个动画加速的中间点,然后从中间点减速,直到动画结束。如图1-2所示,动画的开始和结束移动距离小于中间。
图1-2 一个非线性动画的例子
让我们看在属性动画系统的重要组成部分,如何计算像上面显示的动画的详细介绍。图1-3描述了主要类是怎么工作的。
图1-3 动画是如何计算的
ValueAnimator对象保持动画的实时跟踪,如动画已经运行的时间,和当前动画的属性值。
在ValueAnimator封装TimeInterpolator,它定义动画加速器和TypeEvaluator,它定义了如何计算的动画属性的值。例如,如图1-2,使用的TimeInterpolator是AccelerateDecelerateInterpolator并TypeEvaluator是IntEvaluator的。
启动动画,创建一个ValueAnimator,设定给你想要的动画开始和结束值,定义动画的持续时间。当你调用的start()动画开始。在整个动画,ValueAnimator计算基于动画的持续时间和多少时间已过,介于0和1。经过的部分代表,动画已完成的时间百分比,0表示0%和100%表示1的含义。例如,在图1中,在t 40毫秒。计算经过部分ValueAnimator时,它调用TimeInterpolator当前设置,计算插值分数。一个插值分数经过部分映射到一个新的,考虑到设置的时间内插的分数。例如,在图1-2中,因为动画慢慢加速,插约0.15分数,是比过去0.25部分少,在t = 10毫秒内。在图1-1中,插值分数始终是经过分数相同。
当插值分数计算,ValueAnimator的的调用适当的TypeEvaluator,计算你的动画属性值,基于内插的分数,起始值,结束值和动画。例如,在图1-2中,插值部分是在t=0.15在10毫秒内,所以当时时间属性值为0.15 x(40 - 0)=6。
关于如何使用属性动画,系统的com.example.android.apis.animation包中的API演示示例项目提供了很多例子。
1.5 属性动画和View动画的不同
View动画系统提供的功能只针对View对象,所以如果你想要没View对象也能有动画,你就必须自己写代码了。View动画也拘泥于只能让View对象暴露出来的一些方面形成动画,比如缩放,旋转。如果你想要一个背景色改变的动画呢?View动画不提供。另一个View动画的缺点就是它只是修改了View绘制的位置,并没有实际修改View本身。例如,如果你想要一个按钮横穿一个屏幕的动画,按钮会正确的绘制,但实际上你点击按钮可能没有任何反应。所以你必须实现自己的逻辑。用属性动画的话,就完全没有这些约束了,并且你能针对任意对象的属性来做动画,并且实际上它也真正的被修改。属性动画系统也能以更健壮的方式进行动画。在3.0以上系统中,你分配给动画师一些你想要的动画属性,比如颜色,位置,大小,并且能定义动画的各方面如加速器,多动画的同步。对于View动画系统则只需要很少的代码和一些简单的设置即可,如果View动画能完成一切你想要做的事情,就不用考虑属性动画了。当然你可以结合两种动画系统一起使用。
1.6 API概述
你可以在android.animation里面找到属性动画系统大部分API。因为视图的动画系统已经定义了许多加速器在android.view.animation,你可以使用属性动画系统的加速器。下表描述的属性动画系统的主要组成部分。Animator 类提供了用于创建动画的基本结构。你通常不使用这个类,因为它直接提供最基本的功能,必须扩展到完全支持动画值。以下子类扩展Animator:如下表1-1所示
类 |
描述 |
ValueAnimator |
属性动画主要的计时器引擎,也为属性动画计算相关的值。它有所有的核心功能,计算动画值和包含的每个动画时间的细节,动画是否重复的信息,监听接受更新事件,并且能自定义类型评估。动画属性有两个部分: 计算动画的值并且设置那些值到动画的对象和属性中。ValueAnimator不执行第二部分,所以你必须监听值的更新并修改对象的逻辑。 |
ObjectAnimator |
ValueAnimator的子类允许你设置一个目标对象并让对象属性成为动画。当它为动画计算一个新值时,这个类更新相应的属性。你想要使用ObjectAnimator是因为它让动画赋值的过程更容易。然而,有时候你想要直接的使用 ValueAnimator,因为ObjectAnimator有一些更多的限制,比如要需要具体的访问方法出现在目标对象。 |
AnimatorSet |
提供一个机制来让动画组合到一起。你可以让他们同时播放,串联播放,或在指定延迟后播放。 |
表1-1 Animators(动画师)
求值程序会告诉属性动画系统如何给一个给定的属性计算值。他们花的时间数据,是由一个动画师类提供,动画的起始和结束值,并基于此数据计算动画属性的值。属性动画系统提供了一下评估者:
类/接口 |
描述 |
IntEvaluator |
默认的求值程序为int属性计算值 |
FloatEvaluator |
默认的求值程序为float属性计算值 |
ArgbEvaluator |
默认的求值程序为颜色属性计算值,显示为十六进制格式 |
TypeEvaluator |
一个接口,允许你创建你自己的求值程序。如果你动画对象属性不是int,float或color,你就必须实现TypeEvaluator接口来指定如何计算对象动画属性的值。如果你想要处理这些类型又不同于默认的行为,当然,你可以为int,float或color自定义。 |
表1-2 Evaluators(评估师)
一个时间加速器在一个动画中定义了特定的值,用于作为时间的函数来参与计算。例如,你能指定动画是线性穿越整个动画的,其实就是我们数学中的匀速运动。或者你能指定动画是非线性的,例如,加速或减速运动。表1-3描述了各种加速器,它们都包含在android.view.animation中,如果没有加速器提供适合您的需求,实现TimeInterpolator接口和创建自己的加速器。
类/接口 |
描述 |
AccelerateDecelerateInterpolator |
开始和结束变慢,中间加速 |
AccelerateInterpolator |
慢慢的开始,然后加速 |
AnticipateInterpolator |
开始向后,然后在飞速的向前 |
AnticipateOvershootInterpolator |
开始向后,然后飞速的向前并越过目标值,然后在返回最终的值 |
BounceInterpolator |
碰到改变后回弹 |
CycleInterpolator |
根据指定数量的周期重复 |
DecelerateInterpolator |
开始很快,然后减速 |
LinearInterpolator |
根据一个常量匀速变化 |
OvershootInterpolator |
快速向前然后超过最后的值,然后返回。 |
TimeInterpolator |
一个借口,允许你实现自己的加速器 |
表1-3 Interpolators(加速器)
1.7 ValueAnimator动画
ValueAnimator类让你根据指定了一套整,浮,或颜色值的时间来做动画。你获得通过ValueAnimator调用工厂方法之一:ofInt() , ofFloat() , or ofObject()。例如,代码清单1-1所示:
ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f); animation.setDuration(1000); animation.start();
代码清单1-1
在这段代码中,当start()方法运行时,在持续时间1秒钟内,在0到1之间ValueAnimator开始计算动画值。你也可以指定一个自定义类型的动画通过执行下列操作,如代码清单1-2所示:
ValueAnimator animation = ValueAnimator.ofObject(new MyTypeEvaluator(), startPropertyValue, endPropertyValue); animation.setDuration(1000); animation.start();
代码清单1-2
在这段代码中,ValueAnimator开始计算之间的动画值,使用所提供的逻辑MyTypeEvaluator ,并在start()方法后开始执行,运行时间为1秒,范围为startPropertyValue和endPropertyValue。
然而,前面的代码片段,有没有真正影响一个对象,因为在ValueAnimator不直接操作对象或属性。最有可能的事情,你想要做的是修改这些计算值要进行动画的对象。你可以在ValueAnimator定义监听适当的处理动画的寿命期间的重要事件,如帧更新。实现监听时,你可以通过调用特定的帧刷新计算值getAnimatedValue()。
1.8 ObjectAnimator动画
ObjectAnimator是ValueAnimator的子类并且结合了计时器引擎和ValueAnimator值计算,并且有让一个目标对象变成属性动画的能力。这使任何对象变成动画更容易,因为你不再需要实现ValueAnimator.AnimatorUpdateListener,因为动画属性自动更新。实例化一个ObjectAnimator 和ValueAnimator是相似的,但你也指定对象和对象名称的属性(一个字符串)连同值动画,如代码清单1-3所示:
ObjectAnimator anim = ObjectAnimator.ofFloat(foo, "alpha", 0f, 1f); anim.setDuration(1000); anim.start();
代码清单1-3
为了让ObjectAnimator正确得更新属性,你必须这样做:
1. 你想要对象属性成为动画,就必须有一个setter函数。因为ObjectAnimator自动更新动画属性,它必须能使用setter方法访问这些属性。例如,如果属性的名字是foo,你必须有一个setFoo()方法。如果这个setter方法不存在,你有三种选择
◆如果你有权利这样做,你可以添加setter方法在类中。
◆使用你又权利改变的包装类并且包装程序用一个有效的setter方法接收值,并转发到原始对象。
◆使用ValueAnimator代替
2. 如果你在一个ObjectAnimator工厂方法中只指定一个值,那么它将被认为是动画的结束值。因此,对象属性是动态的,你必须有一个getter函数,用来获得动画的起始值。例如,如果属性的名字是foo,你必须有一个getFoo()方法。
3. 属性的getter和setter方法操作的都必须是同一个类型。例如,像代码清单1-4那样,你有一个targetObject.setPropName(float)方法,那getter方法就必须对应,如targetObject.getPropName(float)
ObjectAnimator.ofFloat(targetObject, "propName", 1f)
代码清单1-4
4. 这取决于你动画是什么属性或对象,你可能需要调用invalidate()方法在视图使屏幕重绘本身与更新的动画值,你可以在onAnimationUpdate()回调方法中这样做。例如Drawable对象的color属性想变成一个动画,只需要更新屏幕,重绘它自己。在View上所有属性设置器,如setAlpha()和setTranslationX()都会刷新View的属性,所以,你不需要在额外的调用刷新方法去刷新View了。
1.9 用AnimatorSet编排多个动画
在很多情况下,你想要播放一个动画取决于另一个动画开始时或者完成后。Android系统让你吧动画捆绑到一个AnimatorSet中,所以你可以指定动画同时播放,依次播放,或延迟后播放。你也可以嵌套AnimatorSet对象,应对更复杂的情况。以下代码片段Bouncing Balls中的例子,下面这些对象是这样播放的:
1. 播放 bounceAnim.
2. 同时播放squashAnim1,squashAnim2,stretchAnim1,stretchAnim2
3. 播放bounceBackAnim.
4. 播放fadeAnim
想要这样的播放顺序,就如下面代码清单1-5所示:
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-5
2.0 动画监听
你能在动画持续时间内监听重要的事件
Animator.AnimatorListener:
onAnimationStart() – 当动画开始时调用
onAnimationEnd() – 当动画结束时调用
onAnimationRepeat() – 当动画重复时调用
onAnimationCancel() -当取消被调用时,End()也会被调用
ValueAnimator.AnimatorUpdateListener
onAnimationUpdate() – 这个方法将在动画的每帧调用。监听这个事件用来计算通过ValueAnimator生成的值。使用这个值来查询ValueAnimator对象传递到这个事件来通过ValueAnimator. getAnimatedValue()方法获得当前的动画值。如果你使用ValueAnimator就必须实现这个监听。这取决于你的动画师什么样的属性或对象,你可能需要调用invalidate()来强制View刷新它所在的屏幕区域的动画值。例如颜色属性的Drawable动画仅仅只有重绘的时候才更新。所有View上的属性设置器,如setAlpha()和()setTranslationX都会适当的刷新。所以你不需要手动调用invalidate()方法来刷新新值。并且在这些set方法中已经包含了invalidate()。
你能继承AnimatorListenerAdapter类来代替实现Animator.AnimatorListener接口,如果你不想要实现接口中所有的方法。AnimatorListenerAdapter更合适,它提供了Animator.AnimatorListener接口中所有的空实现,你只需要重载你需要的方法即可。例如ApiDemo中的BouncingBalls创建了AnimatorListenerAdapter仅仅重载了需要的onAnimationEnd()回调方法。如代码清单1-6所示:
ValueAnimatorAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
fadeAnim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
balls.remove(((ObjectAnimator)animation).getTarget());
}
代码清单1-6
2.1 ViewGroups改变布局时的动画
属性动画系统提供一种能力来动画改变ViewGroup对象以及提供一个简单的方法来激活View对象本身。你能使用LayoutTransition类在一个ViewGroup中动画改变布局。在一个ViewGroup里的View,能有出现和消失的动画,比如当从ViewGroup中添加它们或移除它们或者当你调用setVisibility()时。当你添加或删除View时,剩余的View在ViewGroup也可以通过动画的形式进入他们的新位置。你能定义以下动画,在LayoutTransition对象中调用setAnimator()和以下常量来实现:
◆APPEARING:一个标志,指示动画上运行的item出现在容器中。
◆CHANGE_APPEARING:一个标志,指示动画运行在由于新item出现在容器中发生改变的item上。
◆DISAPPEARING:一个标志,指示动画上运行的item从容器中消失。
◆CHANGE_DISAPPEARING:一个标志,指示动画运行在由于一个在容器中item发生消失改变的item上。
你可以为这四个类型的事件定制的外观布局转换来自定义动画或者只是告诉动画系统使用默认的动画。ApiDemo中有一个LayoutAnimations 例子,告诉你怎样为布局过渡定义动画并且设置你想要的View对象动画。LayoutAnimationsByDefault及其对应的layout_animations_by_default.xml布局资源文件说明如何启用默认布局过渡动画。唯一一件你需要做的就是将android:animateLayoutchanges属性设为true,如代码清单1-7所示:
<LinearLayout android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="match_parent" android:id="@+id/verticalContainer" android:animateLayoutChanges="true" />
代码清单1-7
将这个属性设置为true会在ViewGroup添加或移除View时自动的产生动画。
2.2 使用一个TypeEvaluator
如果你想要在未知的Android系统中激活一个类型的动画,你能通过实现TypeEvaluator接口来创建自己的evaluator。这个已知类型的Android系统为int,float,color,与之对应的有IntEvaluator,FloatEvaluator, ArgbEvaluator。在TypeEvaluator接口中只有一个方法来实现,那就是evaluate()方法。它允许动画师(animator)使用已返回的合适的动画属性值。这个FloatEvaluator类演示了如何做到这一点。如代码清单1-8所示:
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); } }
代码清单1-8
注意:当ValueAnimator(或ObjectAnimator)运行时,它计算当前运行部分的动画(值在0和1之间),然后计算一个你正在使用的加速器版本。加速器的分数是你TypeEvaluator通过fraction参数接受到的,所以当计算动画值时,你不需要考虑加速器
2.3 使用加速器(interpolator)
一个加速器定义了如何在一个动画中作为时间函数来指定其值,例如你能指定动画是匀速或非匀速贯穿整个动画,这取决于你使用什么样的加速器。Android系统系统一套常见的加速器在android.view.animation package包中。如果没有你想要的加速器,你可以通过TimeInterpolator自己实现。作为一个例子,我们看下如下加速器的实现代码:
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; }
其实这就好比我们在使用物理和数学的知识来套用公式了。以下表格就是毫秒间隔时间内的值,如表1-4所示:
逝去的时间(毫秒) |
匀速(Linear) |
加速/减速 |
0 |
0 |
0 |
200 |
0.2 |
0.1 |
400 |
0.4 |
0.345 |
600 |
0.6 |
0.8 |
800 |
0.8 |
0.9 |
1000 |
1 |
1 |
表1-4 匀速和变速的数值比较
2.4 指定关键帧
一个KeyFrame(关键帧)对象由时间和具体值组成,让你在指定的时间内,定义一个指定的状态。每个关键帧能有她自己的加速器来控制动画的行为,它的区间为前面的关键帧的时间与目前关键帧时间的间隔时间。为了实例化一个Keyframe对象,你必须使用工厂方法,如ofInt(), ofFloat(), ofObject()以获得适当类型的Keyframe(关键帧)。你调用PropertyValuesHolder.ofKeyframe()方法来获得一个PropertyValuesHolder对象。一旦你有了这个对象,你就能获得一个animator(动画师) 对象了。以下代码片段演示了如何做到这一点,如代码清单1-9所示:
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);
代码清单1-9
关于如何使用关键帧,如果你想看更完整的例子,请在APIDemos中查阅MultiPropertyAnimation例子。
2.5 让View动起来
属性动画允许一些合理的View对象拥有动画并提供一些比View动画系统更有力的特性。View动画系统通过View对象的变形来形成动画,View依然在那绘制。这会处理容器中的每一个View,因为View它自己没有属性来操作。这造成View动画并没有改变View对象本身,这导致一些很不愉快的开发体验。在Android3.0和之后的版本中,新属性和相应的getter和setter方法的添加以消除这个缺点。
属性动画系统可以设置动画视图在屏幕上通过改变实际的属性视图对象。此外, 每当其属性被更改时,View还自动调用invalidate()方法来刷新屏幕。View类中的新属性会使属性动画更容易实现:
◆
translationX
和translationY
:这个属性控制了View的平移位置
◆
rotation
,rotationX
, and rotationY
:这些属性控制了2D旋转和3D旋转中心点
◆
scaleX
和scaleY
:这些属性控制了2D围绕它的中心点的缩放
◆
pivotX
和pivotY
:这些属性控制中心点的位置,因为旋转,缩放,位移都是根据中心点进行的。默认情况下,中心点在对象的中间(非左上哦,请注意!)
◆
x
和y
:这些都是简单的实用属性来描述View在它的容器中的最终位置,是左边,顶部translationX 和translationY的总和
◆
alpha
:表示View上alpha的透明度。默认值为1表示不透明,0表示完全透明。
让一个View对象动起来,如颜色和旋转值,所有你需要做的就是创建一个animator并指定你想要他动起来的View中的某个属性,例如代码清单1-10所示:
ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f);
代码清单1-10
ViewPropertyAnimator
ViewPropertyAnimator提供一个简单的方法来
让几个View属性同时动起来,它的行为就像一个ObjectAnimator,因为他修改View属性的实际值,但当许多属性动画运行时,它更高效。此外,使用ViewPropertyAnimator的代码更简洁、更容易阅读。下面代码片段展示了它与ObjectAnimator的差异,如代码片段所示:
多个 ObjectAnimator对象
ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f); ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f); AnimatorSet animSetXY = new AnimatorSet(); animSetXY.playTogether(animX, animY); animSetXY.start();
一个 ObjectAnimator对象
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定义你的动画,你可以很容易的在多个activity重用你的动画并更容易编辑动画序列。为了区分你使用新的属性动画系统API还是以前老的view动画系统,你应该分别保存XML文件,如res/animator/
目录保存的是新的属性动画文件,
res/anim/
为旧的View动画系统文件。虽然你不一定非要使用
res/animator/
目录,但如果你需要在Eclipse中使用布局编辑工具的话,你就必须使用
res/animator/
目录,因为ADT只会搜索这个名字的文件夹。
以下属性动画类有XML声明支持以下XML标记:
ValueAnimator - <animator>
ObjectAnimator - <objectAnimator>
AnimatorSet - <set>
让我们看下代码清单1-11的例子:
<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>
代码清单1-11
为了执行这个动画,你必须在代码中inflate XML资源到AnimatorSet对象中,然后为所有的动画设置目标对象。具体请看代码清单1-12所示:
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext, R.anim.property_animator); set.setTarget(myObject); set.start();
代码清单1-12