属性动画的特性
1.Duration(持续时间)
2.时间插着器(Time interpolation):指定这个属性的值变化的方式。比如,变化越来越快,或是越来越慢。
3.重复的次数和方式(Repeat count and behavior):你可以指定动画是否重复播放、重复的次数、重复的方式(从头到尾正向重复还是从尾到头反向重复)
4.动画集合(Animator sets):将多个动画组织成一个逻辑集合,你可以让这些动画同时播放,或是一个一个顺序播放,或是其他逻辑。
5.帧刷新频率(Frame refresh delay):即,属性的值得刷新频率。系统默认10ms,不过实际刷新频率,还是又系统的繁忙程度和系统时钟的快慢来决定的。
时间插值器(TimeInterpolator)
一句话总结时间插值器的作用:根据当前的时间进度比,计算出当前动画进度比例。
TimeInterpolator本身是一个接口,它的实现类决定了动画变化的速度。你如果不想让你的动画是线性匀速变化,比如加速或减速变化,就需要实现这个方法。
//接口代码
public interface TimeInterpolator {
float getInterpolation(float input);
}
getInterpolation()方法的参数:input = 过去的时间 / 总时间。表示动画的当前时间位置,0表示开始,1.0表示结束。
getInterpolation()的返回值则表示经过插值计算之后的值,一般在0-1之间,不过,这个返回值可能存在小于0和大于1的情况,这是为了实现越界反弹等动画效果。
线性插值器LinearInterpolator的getInterpolation()只是简单的将input返回,方法体如下
public float getInterpolation(float input) {
return input;
}
加速插值器AccelerateInterpolator的getInterpolation()默认情况下回返回input的平方。
public float getInterpolation(float input) {
if (mFactor == 1.0f) {
return input * input;
} else {
return (float)Math.pow(input, mDoubleFactor);
}
}
类型求值器(TypeEvaluator)
TypeEvaluator根据当前时间点的动画进度,计算出属性当前时间点的值。
在上面我们知道TimeInterpolator根据当前的时间进度比,计算出动画进度应有的比例。那么TypeEvaluator就是根据这个动画进度参数、属性初始值,属性最终值,就算出当前时间下的属性的值。
//TypeEvaluator接口代码
public interface TypeEvaluator<T> {
//根据动画进度,属性起始值和结束值,计算出当前值
public T evaluate(float fraction, T startValue, T endValue);
}
TypeEvaluator是用来计算属性值,它的实现类有IntEvaluator, FloatEvaluator, ArgbEvaluator等,分别用于不同类型的属性。比如你的属性是int类型的,则对应IntEvaluator。
//IntEvaluator的实现
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
int startInt = startValue;
return (int)(startInt + fraction * (endValue - startInt));
}
Property Animation 和 View Animation的区别
- View Animation 只能用于View及View的子类的对象;Property Animation则没有这样的限制
2.View Animation限制较多,一些动画,只能用于没有background的view,否则会打不到预期效果;如,缩放一个view时,这是缩小了view的外观,她的background并没有改变,所以如果background不是透明的,则会露馅。
3.View Animation只是简单的改变View的绘制,并不会改变View本身。比如,你将一个button从位置1移动到位置2,但是触发点击事件的位置还是在位置1。Property Animation这不会出现这种情况。 - View Animation 使用的代码较少,启动所花费的时间也短,如果View Animation能够达到你想要的效果,你同样可以继续使用它。你可以根据情况的不同,选择使用哪种动画。
ValueAnimator
举个栗子
ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f);
animation.setDuration(1000);
animation.start();
上面这段代码中,ValueAnimator在1000ms内,在0f-1f之间,不断地改变这个浮点类型的值,0f是开始值,1f是结束值。
ValueAnimator有工厂方法ofInt()、ofFloat()、ofObject()用于不同的类型。
对于自定义类型,你可以这样:
ValueAnimator animation = ValueAnimator.ofObject(new MyTypeEvaluator(), startPropertyValue, endPropertyValue);
animation.setDuration(1000);
animation.start();
在这段代码中,ValueAnimator在开始值startPropertyValue和结束值endPropertyValue之间,不断的计算属性值。
上面的代码并没有真正作用到一个对象上,除了属性值的改变,你观察不到任何变化。如果你想达到当属性值变化的同时,让某个对象(外观、内容等任意)也随之改变,你需要为这个ValueAnimator设置Animation Listeners.当属性动画时间周期内发生重要事件,比如帧刷新,此Listener可以通过getAnimatedValue()得到这个属性在此时的值,然后根据这个值,去做相应的操作,比如移动控件的位置,改变大小等。
ObjectAnimator
ObjectAnimator是ValueAnimator的子类。其让属性动画作用于任何对象都变得很简单,而不再需要实现ValueAnimator.AnimatorUpdateListener,因为这个对象的属性会自动的刷新。
举个栗子
ObjectAnimator anim = ObjectAnimator.ofFloat(foo, "alpha", 0f, 1f);
anim.setDuration(1000);
anim.start();
ObjectAnimator会不断的改变对象foo的透明度。
foo对象的类中必须有setAlpha(float alpha)成员函数
ObjectAnimator注意事项
1.动画作用于的目标对象的属性必须有set<propertyName>()形式的setter方法。ObjectAnimator通过这个方法更新此属性的值。
2.如果你没有为参数values...提供起始值,比如,ObjectAnimator.ofFloat(foo, "alpha")或ObjectAnimator.ofFloat(foo, "alpha",1f)(提供一个值,则作为结束值),你必须提供getter方法,形如get<propertyName>(),如getAlpha();
3.getter和setter方法的参数类型必须和ObjectAnimator.ofXXX(targetObject,"propName",values...)的values的类型相同。
4.根据用于动画的属性的不同,你可能需要调用view的invalidate()方法强制在重绘view。你可以在onAnimationUpdate()中调用invalidate();比如,Drawable的color属性,只有当此Drawable重绘时才会引起屏幕刷新。
Animation Listeners
你可以用下面的Listener监听动画,一边在重要事件发生是,有所操纵。
Animator.AnimatorListener
-
onAnimationStart()
当动画启动时调用. -
onAnimationEnd()
当动画结束时调用. -
onAnimationRepeat()
当动画重播时调用. -
onAnimationCancel()
当动画取消时调用. 同样onAnimationEnd()
也会被调用, 不管动画是怎样结束的.
ValueAnimator.AnimatorUpdateListener
-
onAnimationUpdate()
帧刷新时调用。监听这个事件,用于使用ValueAnimator计算出的属性值。通过ValueAnimator#getAnimatedValue()方法获得属性值。
AnimatorListenerAdapter -- 用与代替Animator.AnimatorListener
如果你不想实现AnimatorListener的所有方法,你可以使用AnimatorListenerAdapter代替,AnimatorListenerAdapter使用空方法实现了AnimatorListener的所有方法。
举个栗子
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());
}
}
布局动画
属性动画同样可以想应用于View那样方便的应用于ViewGroup。通过调用ViewGroup#setLayoutTransition(LayoutTransition)方法为其设置
你可以通过使用LayoutTransition的方法[setAnimator()](http://developer.android.com/reference/android/animation/LayoutTransition.html#setAnimator(int, android.animation.Animator)),并传入一个 Animator和一个下面的常量(定义在LayoutTransition中)值作为参数,来定制用于ViewGroup的动画。
- APPEARING
指明这个动画是用于当某个条目显示出来时使用. - CHANGE_APPEARING
指明当有条目显现时,这个动画用于其他item. - DISAPPEARING
指明这个动画是用于当某个条目隐藏时使用. - CHANGE_DISAPPEARING
指明当有条目隐藏时,这个动画用于其他item.
你可以在ViewGroup的xml中添加android:animateLayoutchanges="true"来为ViewGroup指定默认动画。
栗子
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="@+id/verticalContainer"
android:animateLayoutChanges="true" />
指定关键帧 Keyframes
一个Keyframe对象有一个time/value对组成,用于指定在特定时间点,动画的状态。每一个关键帧都可以有它自己的插值器,用来控制前一个关键帧和此关键帧的关系。
- 你必须使用方法ofInt(), ofFloat(), 和ofObject()中的一个来获得一个关键帧实例。
- 然后调用PropertyValuesHolder的工厂方法[ofKeyframe()](http://developer.android.com/reference/android/animation/PropertyValuesHolder.html#ofKeyframe(android.util.Property, android.animation.Keyframe...))来获得一个PropertyValuesHolder对象。
- 然后,将PropertyValuesHolder对象作为ObjectAnimator.ofPropertyValuesHolder()方法的参数,即可构造出一个对象。
栗子
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);