前言
《Android开发艺术探索》第三章弹性滑动中有这么一段话:”如何实现弹性滑呢?实现方法有很多,但它们都有一个共同的思想:将一次大的滑动分成若干次小的滑动并在一个时间段内完成,其实现方式有很多种,Scroller、Handler.postDelayed()、Thread.sleep()等“;我们将这段话套用到Android动画上:将一次大的属性变化(如透明度从1到0)分成很多次小的属性变化并在一个时间段内完成(16.7ms内完成),从而实现透明度渐变动画效果,其实现方式是通过Choreographer来完成的;Choreographer是动画原理的一个核心,搞明白动画工作原理之前我们需要先了解Choreographer工作过程;
Choreographer工作过程简单描述如下:在Choreographer对象中有四条链表,分别保存着待处理的输入事件,待处理的动画事件,待处理的View绘制事件、待处理的post到Choreographer中事件,Android系统每隔16.7ms发出VSYNC信号,Choreographer.FrameDisplayEventReceiver收到信号后调用onVsync方法,最终会调用Choreographer.doFrame()方法,在doFrame方法中处理输入事件、动画事件、View绘制、post到Choreographer中的FrameCallback;我们可以使用Choreographer#postFrameCallback设置callback与Choreographer交互,设置的FrameCallCack(doFrame方法)会在下一个frame被渲染时触发(即下一个VSYNC到来时执行);Choreographer更多内容请参考Android Choreographer 源码分析
Android动画原理简单描述:将View的一次大的属性变化拆分为多次小的属性变化,在每次VSYNC信号到来时,根据当前时间和插值器来计算当前View属性的值,然后给View设置该属性值,直到动画执行完毕。其中Choreographer将动画拆分成一次次小的属性变化,Choreographer是动画的指挥者。理想情况下,属性刷新次数(动画拆分为多次小的属性变化) = 动画执行时间/16.7ms 。
我们通过属性动画工作流程来介绍Android动画工作原理,其它动画的工作过程也应该类似,感兴趣的可以阅读源码来了解其原理;本文主要围绕以下四个问题来讲解动画原理:
问题一:动画如何完成一次属性变化刷新?
问题二:动画如何被拆分成一次次小的属性变化?
问题三:动画如何跳出属性刷新的流程,从而结束动画?
问题四:动画监听器何时被调用?
属性动画简单例子
在讲解原理前,我们先来看一下属性的动画的一个简单例子:
public class AnimationActivity extends AppCompatActivity implements View.OnClickListener{
private Button mButton;
public static final String TAG = "AnimationTest";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.animation_layout);
mButton = (Button) findViewById(R.id.button);
mButton.setOnClickListener(this);
}
@Override
public void onClick(View v) {
//ObjectAnimator extends ValueAnimator;
ValueAnimator alphaAnimation = ObjectAnimator.ofFloat(mButton,"alpha",1.0f,0f);
alphaAnimation.setDuration(100);
alphaAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//属性刷新
Log.d(TAG, "onAnimationUpdate: " + animation.getAnimatedValue());
}
});
alphaAnimation.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
//动画开始
Log.d(TAG, "onAnimationStart: ");
}
@Override
public void onAnimationEnd(Animator animation) {
//动画结束
Log.d(TAG, "onAnimationEnd: ");
}
@Override
public void onAnimationCancel(Animator animation) {
Log.d(TAG, "onAnimationCancel: ");
}
@Override
public void onAnimationRepeat(Animator animation) {
Log.d(TAG, "onAnimationRepeat: ");
}
});
alphaAnimation.start();
}
}
运行之后,我们点击Button,对Button开始做透明度动画,相关日志打印如下:
01-28 10:15:39.587 3867-3867/com.android.animation D/AnimationTest: onAnimationStart:
0