Android Animation--Property Animation

属性动画,这个是在Android 3.0中才引进的,与view animation 最大的不同就是,它更改的是对象的实际属性,而View Animation(Tween Animation)中,其改变的是View的绘制效果,真正的View的属性保持不变,比如无论你在对话中如何缩放Button的大小,Button的有效点击区域还是没有应用动画时的区域,其位置与大小都不变。而在Property Animation中,改变的是对象的实际属性,如Button的缩放,Button的位置与大小属性值都改变了。而且Property Animation不止可以应用于View,还可以应用于任何对象。Property Animation只是表示一个值在一段时间内的改变,当值改变时要做什么事情完全是你自己决定的。

在Property Animation中,可以对动画应用以下属性:

Duration:动画的持续时间
TimeInterpolation:属性值的计算方式,如先快后慢
TypeEvaluator:根据属性的开始、结束值与TimeInterpolation计算出的因子计算出当前时间的属性值
Repeat Count and behavoir:重复次数与方式,如播放3次、5次、无限循环,可以此动画一直重复,或播放完时再反向播放
Animation sets:动画集合,即可以同时对一个对象应用几个动画,这些动画可以同时播放也可以对不同动画设置不同开始偏移
Frame refreash delay:多少时间刷新一次,即每隔多少时间计算一次属性值,默认为10ms,最终刷新时间还受系统进程调度与硬件的影响

ValueAnimator

ValueAnimator 表示一个动画,包含动画的开始值,结束值,持续时间等属性。
ValueAnimator封装了一个TimeInterpolator,TimeInterpolator定义了属性值在开始值与结束值之间的插值方法。
ValueAnimator还封装了一个TypeAnimator,根据开始、结束值与TimeIniterpolator计算得到的值计算出属性值。
ValueAnimator的父类和子类如图:
value-anim{ImgCap}value-animator.png{/ImgCap}
ValuAnimiator只完成了第一步工作,如果要完成第二步,需要实现ValueAnimator.onUpdateListener接口,这个接口只有一个函数onAnimationUpdate(),在这个函数中会传入ValueAnimator对象做为参数,通过这个ValueAnimator对象的getAnimatedValue()函数可以得到当前的属性值如:

1
2
3
4
5
6
7
8
9
10
ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f);
animation.setDuration(1000);
animation.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Log.i("update", ((Float) animation.getAnimatedValue()).toString());
}
});

animation.setInterpolator(new CycleInterpolator(3));
animation.start();

对于下图的动画,这个对象的X坐标在40ms内从0移动到40 pixel.按默认的10ms刷新一次,这个对象会移动4次,每次移动40/4=10pixel。

animation1

也可以改变属性值的改变方法,即设置不同的interpolation,在下图中运动速度先逐渐增大再逐渐减小
animation2

  • Animator.AnimatorListener

    • onAnimationStart() - 动画开始时调用
    • onAnimationEnd() - 动画结束时调用
    • onAnimationRepeat() - 动画重复时调用
    • onAnimationCancel() - 动画被取消时调用,同时会调用onAnimationEnd()
  • ValueAnimator.AnimatorUpdateListener

    • onAnimationUpdate() -绘制动画的每一帧都会被调用

有时我们没有必要实现AnimatorListener 接口,可以用适配器类 AnimatorListenerAdapter代替有时我们没有必要实现AnimatorListener 只实现你想要的方法。

ObjectAnimator

ValueAnimator的子类,要指定一个对象及该对象的一个属性,当属性值计算完成时自动设置为该对象的相应属性,即完成了Property Animation的全部两步操作。实际应用中一般都会用ObjectAnimator来改变某一对象的某一属性,但用ObjectAnimator有一定的限制,要想使用ObjectAnimator,应该满足以下条件:

  • 对象应该有一个setter函数:set(驼峰命名法)
  • 如上面的例子中,像ofFloat之类的工场方法,第一个参数为对象名,第二个为属性名,后面的参数为可变参数,如果values…参数只设置了一个值的话,那么会假定为目的值,属性值的变化范围为当前值到目的值,为了获得当前值,该对象要有相应属性的getter方法:get
  • 如果有getter方法,其应返回值类型应与相应的setter方法的参数类型一致。
    如果上述条件不满足,则不能用ObjectAnimator,应用ValueAnimator代替。
1
2
3
ObjectAnimator oa=ObjectAnimator.ofFloat(tv, "alpha", 0f, 1f);
oa.setDuration(5000);
oa.start();

上面这段代码就是让textview的alpha属性从0f在5s内变化到1f ,即从完全不可见到完全可见。

常用的属性有:alpha,translationX,translationY,translationZ,rotation,rotationX,scaleX,scaleY…

AnimatorSet

AnimationSet提供了一个把多个动画组合成一个组合的机制,并可设置组中动画的时序关系,如同时播放,顺序播放等。

实现组合动画功能主要需要借助AnimatorSet这个类,这个类提供了一个play()方法,如果我们向这个方法中传入一个Animator对象(ValueAnimator或ObjectAnimator)将会返回一个AnimatorSet.Builder的实例,AnimatorSet.Builder中包括以下四个方法:

  • after(Animator anim) 将现有动画插入到传入的动画之后执行
  • after(long delay) 将现有动画延迟指定毫秒后执行
  • before(Animator anim) 将现有动画插入到传入的动画之前执行
  • with(Animator anim) 将现有动画和传入的动画同时执行

以下例子同时应用5个动画:

  1. 播放a1;
  2. 同时播放a2,a3,a4;
  3. 播放anim5。
1
2
3
4
5
6
7
8
9
10
11
ObjectAnimator a1 = ObjectAnimator.ofFloat(animTextView, "translationX", -500f, 0f);
ObjectAnimator a2 = ObjectAnimator.ofFloat(animTextView, "rotation", 0f, 360f);
ObjectAnimator a3 = ObjectAnimator.ofFloat(animTextView, "alpha", 1f, 0f, 1f);
ObjectAnimator a4 = ObjectAnimator.ofFloat(animTextView, "scaleY", 1f, 2f, 1f);
ObjectAnimator a5 = ObjectAnimator.ofFloat(animTextView, "scaleX", 1f, 2f);
AnimatorSet animSet = new AnimatorSet();
animSet.play(a1).before(a2);
animSet.play(a2).with(a3);
animSet.play(a2).with(a4);
animSet.play(a5).after(a2);
animSet.start();

TypeEvalutors

根据属性的开始、结束值与TimeInterpolation计算出的因子计算出当前时间的属性值,android提供了以下几个evalutor:

IntEvaluator:属性的值类型为int;
FloatEvaluator:属性的值类型为float;
ArgbEvaluator:属性的值类型为十六进制颜色值;
TypeEvaluator:一个接口,可以通过实现该接口自定义Evaluator。
自定义TypeEvalutor很简单,只需要实现一个方法,如FloatEvalutor的定义:
ValueAnimator.ofFloat()方法就是实现了初始值与结束值之间的平滑过度,那么这个平滑过度是怎么做到的呢?其实就是系统内置了一个FloatEvaluator,它通过计算告知动画系统如何从初始值过度到结束值

1
2
3
4
5
6
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);
}
}

View处于不同的状态改变时应用动画

ViewGroup中的子元素可以通过setVisibility使其Visible、Invisible或Gone,当有子元素可见性改变时(VISIBLE、GONE),可以向其应用动画,通过LayoutTransition类应用此类动画:

transition.setAnimator(LayoutTransition.DISAPPEARING, customDisappearingAnim);
通过setAnimator应用动画,第一个参数表示应用的情境,可以以下4种类型:

  • APPEARING        当一个元素在其父元素中变为Visible时对这个元素应用动画
  • CHANGE_APPEARING    当一个元素在其父元素中变为Visible时,因系统要重新布局有一些元 素需要移动,对这些要移动的元素应用动画
  • DISAPPEARING       当一个元素在其父元素中变为GONE时对其应用动画
  • CHANGE_DISAPPEARING  当一个元素在其父元素中变为GONE时,因系统要重新布局有一些元素需要移动,这些要移动的元素应用动画.
    第二个参数为一Animator。

mTransitioner.setStagger(LayoutTransition.CHANGE_APPEARING, 30);
此函数设置动画延迟时间,参数分别为类型与时间。

ViewPropertyAnimator

ViewPropertyAnimator提供了一种简单的方式来为View的部分属性设置动画,使用一个单一的Animator对象。它表现的更像 ObjectAnimator,因为他也要修改View对象的相应的属性值,但是当为多个属性同时设置动画时,它比 ObjectAnimator更高效,下面的代码片段显示了使用多个ObjectAnimator,单个ObjectAnimator,以及ViewPropertyAnimator来同时为View的x,y属性设置动画的情形:

1
2
3
4
5
ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();

1
2
3
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();
1
myView.animate().x(50f).y(100f);

注:Property Animation是在API11(android3.0)引入的,如果想兼容API11之前版本,可以使用 NineOldAndroids 开源框架。