由于Android3.0之前已有的动画框架Animation存在一些局限性——动画改变的只是显示,并不能响应事件。因此,在Android3.0之后,Google就提出了属性动画这样一个新的动画框架,帮助开发者实现更加丰富的动画效果。
而在Animator框架中使用最多的就是AnimationSet和ObjectAnimator配合,使用ObjectAnimator进行更精细化控制,只控制一个对象的一个属性,而使用多个ObjectAnimator组合到AnimatorSet形成一个动画。而且ObjectAnimator能够自动驱动,可以调用setFrameDelay(longframeDelay)设置动画帧之间的间隙事件,调整帧率,减少动画过程中频繁绘制界面,而在不影响动画效果的前提下建设CPU资源消耗。最重要的时,属性动画通过调用属性的set、get方法来真实地控制了一个View的属性值,因此强大的属性动画框架基本可以实现所有的动画效果。
下面先来看看属性动画中最基础的ObjectAnimator。
ObjectAnimator时属性动画框架中最重要的实行类,创建一个ObjectAnimator只需要通过它的静态工厂类直接返回一个ObjectAnimator对象。参数包括一个对象和对象的属性名字,但这个属性必须有get和set函数,内部会通过Java的反射机制来调用set函数修改对象属性值。同样,你可以可以调用setInterpolator设置相应的差值器。下面这个小例子就完成了一个非常简单的平移动画。
在前面的讲解中说到,以前的动画框架所产生的动画,并不能改变事件响应的位置,它只是单纯的修改了显示。如果使用旧的视图动画产生上面的效果,那么按钮的实际点击有效区依然在原来的地方,点击移动后的地方是是不会有点击事件发生的。而属性动画则不同,由于它真实地改变了一个View的属性,所以事件响应区域也同样发生了改变,这时候点击移动后的按钮,就会有响应点击事件了。
讲了这么多,让我们来看看这个简单的平移动画是如何实现的。麻雀虽小五脏俱全,这个简单的例子基本上就涵盖了ObjectAnimator的所有知识。
ObjectAnimator oa = ObjectAnimator.ofFloat(imageView, "translationX", 300);
oa.setDuration(1000);
oa.start();
public class WrapperView {
private View mTarget;
public WrapperView(View target) {
mTarget = target;
}
public int getWidth() {
return mTarget.getLayoutParams().width;
}
public void setWidth(int width) {
mTarget.getLayoutParams().width = width;
mTarget.requestLayout();
}
}
WrapperView wrapperView = new WrapperView(imageView);
ObjectAnimator.ofFloat(wrapperView, "width", 500).setDuration(5000).start();
PropertyValuesHolder pvh1 = PropertyValuesHolder.ofFloat("translationX",300);
PropertyValuesHolder pvh2 = PropertyValuesHolder.ofFloat("scaleX",1f,0,1f);
PropertyValuesHolder pvh3 = PropertyValuesHolder.ofFloat("scaleY",1f,0,1f);
ObjectAnimator.ofPropertyValuesHolder(imageView,pvh1,pvh2,pvh3).setDuration(1000).start();
ValueAnimator animator = ValueAnimator.ofFloat(0,100);
animator.setTarget(imageView);
animator.setDuration(1000).start();
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
//TODO use the value
}
});
ObjectAnimator anim = ObjectAnimator.ofFloat(imageView,"alpha",0.5f);
anim.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation, boolean isReverse) {
}
});
ObjectAnimator animator1 = ObjectAnimator.ofFloat(imageView,"translationX",300);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(imageView,"scaleX",1f,0,1f);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(imageView,"scaleY",1f,0,1f);
AnimatorSet set = new AnimatorSet();
set.setDuration(1000);
set.playTogether(animator1,animator2,animator3);
set.start();
Animator animator = AnimatorInflater.loadAnimator(this, R.animator.object_anim);
animator.setTarget(imageView);
animator.start();
imageView.animate()
.alpha(0.3f)
.y(300)
.setDuration(300)
.withStartAction(new Runnable() {
@Override
public void run() {
}
})
.withEndAction(new Runnable() {
@Override
public void run() {
}
}).start();