动画执行从View.startAnimation(animation)开始
->invalidateInternal->ViewGroup.invalidateChild->层层遍历->
ViewRootImpl.invalidateChildInParent->invalidateRectOnScreen->scheduleTraversals->performTraversals
ViewGroup.dispatchDraw->具体到每个View去draw itself -> View.draw(canvas , transientChild , drawingTime)
经过层层处理,动画的具体执行在View.draw方法中
draw(Canvas canvas , ViewGroup parent , long drawingTime){
Animation a = getAnimation();// startAnimation设置的Animation
if(a!=null){
applyLegacyAnimation
}
}
applyLegacyAnimation(){
1) onAnimationStart -> mPrivateFlags |= PFLAG_ANIMATION_STARTED;
2)getTransformation 返回值标识动画是否执行完->执行次数,时间是否完成都在考虑范围内 ; 根据这个方法
的返回值,决定后续是否继续调用invalidate ,又会走遍历View的流程,又会执行动画处理
}
getTransformation(){
applyTransformation // 方法的具体实现在Animation的子类中体现
}
总结:
1、首先,当调用了 View.startAnimation() 时动画并没有马上就执行,而是通过 invalidate() 层层通知到 ViewRootImpl 发起一次遍历 View 树的请求,而这次请求会等到接收到最近一帧到了的信号时才去发起遍历 View 树绘制操作。
2、从 DecorView 开始遍历,绘制流程在遍历时会调用到 View 的 draw() 方法,当该方法被调用时,如果 View 有绑定动画,那么会去调用applyLegacyAnimation(),这个方法是专门用来处理动画相关逻辑的。
3、在 applyLegacyAnimation() 这个方法里,如果动画还没有执行过初始化,先调用动画的初始化方法 initialized(),同时调用 onAnimationStart() 通知动画开始了,然后调用 getTransformation() 来根据当前时间计算动画进度,紧接着调用 applyTransformation() 并传入动画进度来应用动画。
4、getTransformation() 这个方法有返回值,如果动画还没结束会返回 true,动画已经结束或者被取消了返回 false。所以 applyLegacyAnimation() 会根据 getTransformation() 的返回值来决定是否通知 ViewRootImpl 再发起一次遍历请求,返回值是 true 表示动画没结束,那么就去通知 ViewRootImpl 再次发起一次遍历请求。然后当下一帧到来时,再从 DecorView 开始遍历 View 树绘制,重复上面的步骤,这样直到动画结束。
5、有一点需要注意,动画是在每一帧的绘制流程里被执行,所以动画并不是单独执行的,也就是说,如果这一帧里有一些 View 需要重绘,那么这些工作同样是在这一帧里的这次遍历 View 树的过程中完成的。每一帧只会发起一次 perfromTraversals() 操作。