在Animator 框架中,使用最多的就是AnimatorSet和ObjectAnimator配合,使用ObjectAnimator进行更加精细的控制,只控制一个对象的一个属性值,尔斯用多个ObjectAnimator组合到AnimatorSet形成一个动画。而且ObjectAnimator能够自动驱动,可以调用setFrameDelay(longframeDelay)设置动画帧之间的见习时间,调整帧率,减少动画过程中频繁绘制界面,而在不影响动画效果的前提下减少CPU的资源消耗。最重要的是,属性动画是通过调用get、set方法来真实的控制各View的属性值,基本可以实现所有的动画效果。所以View必须要提供setXxx方法,如果动画的时候没有传递初始值,那么还要提供getXxx方法,因为系统要去拿xxx属性的初始值(如果这条不满足,程序直接Crash) 。View的setXxx对属性xxx所做的改变必须能够通过某种方法反映出来,比如会带来ui的改变啥的(如果这条不满足,动画无效果但不会Crash)。
举一个最简单的例子:
ObjectAnimator animator = ObjectAnimator.ofFloat(btn1, "translationX", 0, 500);
animator.setDuration(3000);
animator.start();
ObjectAnimator.ofFloat(btn1, “translationX”, 0, 500); 这里第一个参数是要操纵的view,我的是一个button,第二个参数是要操纵的属性,最后一个参数是一个可变数组参数,传入属性变化的取值过程。和视图动画一样可以设置动画时长等属性。
常见的属性值:translationX、translationY:view对象从他布局容器的左上角坐标偏移的位置
rotation、rotationX、rotationY:控制view围绕支点进行2D、3D的旋转
scaleX、scaleY:控制view对象围绕支点进行2D缩放
pivotX、pivotY:view对象的支点位置,围绕这个支点旋转缩放,默认为view对象的中心店
x、y:view在容器中的位置
alpha:view的透明度
ObjectAnimator.ofFloat使用时要注意属性的数据类型,比如translationX属性使用了ObjectAnimator.ofInt(….)方法时,就会被认为报Method setTranslationX() with type int not found on target class 错误;同样一个属性没有对应get、set方法时,属性动画是不是就没办法了呢?答案肯定是否定的。可以通过一个自定义属性类或者包装类来间接的给这个属性增加get、set方法。
例如:
private static class ViewWrapper {
private View mTarget;
public ViewWrapper(View target) {
mTarget = target;
}
public int getWidth() {
return mTarget.getLayoutParams().width;
}
public void setWidth(int width) {
mTarget.getLayoutParams().width = width;
mTarget.requestLayout();
}
}
这样就给属性包装了一层,使用时只要操纵包装类即可:
ViewWrapper wrapper = new ViewWrapper(mButton);
ObjectAnimator.ofInt(wrapper, width, 500).setDuration(5000).start();
在视图动画中用AnimationSet可以实现多个动画一起执行,在属性动画中,针对一个对象的多个属性进行操控,完成类似AnimationSet的效果可以通过PropertyValuesHolder来实现。
例如:
PropertyValuesHolder pvh1 = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f);
PropertyValuesHolder pvh2 = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f);
PropertyValuesHolder pvh3 = PropertyValuesHolder.ofFloat("translationX",0, 500);
ObjectAnimator.ofPropertyValuesHolder(view,pvh1,pvh2,pvh3).setDuration(3000).start();
ValueAnimator在属性动画中占非常重要的地位。他本身不提供任何动画效果,它更像一个数值发生器,用来产生一定规律的数字,从而让调动着来控制动画的实践过程。ValueAnimator的一般使用方法如下所示,通常情况下,在ValueAnimator的AnimatorUpdateListenerListener中监听数值的变化,从而完成动画的变换。
ValueAnimator animator = ValueAnimator.ofFloat(0,100);
animator.setTarget(view);
animator.setDuration(1000).start();
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Float value = (Float)animation.getAnimatedValue();
//use the value
}
});
一个完整的动画有Start、Repat、End、Cancel四个过程,通过Android提供了接口,可以很方便的监听这四个事件:
animator.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) {
}
});
大部分时候只关心onAnimationEnd事件,所以Android也提供了一个animatorListenerAdapter来让我们选择必要时间进行监听:
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
}
});
对于一个属性同时作用多个属性动画效果,可以用PropertyValuesHolder实现,但是用AnimatorSet不仅能实现这样的效果还可以更加精确的顺序控制。
ObjectAnimator animator1 = ObjectAnimator.ofFloat(view, "translationX",500f);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(view, "scaleX",1f,0f,1f);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(view, "scaleY",1f,0f,1f);
AnimatorSetset = new AnimatorSet();
set.setDuration(2000);
set.playSequentially(animator1,animator2,animator3);
set.start();
在属性动画中AnimatorSet正是通过playTogether()、playSequentially()、animSet.play().with()、before()、after()这些方法来控制多个动画协同工作,从而做到对动画播放顺序的精确控制。