本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布
这次想来梳理一下 View 动画也就是补间动画(ScaleAnimation, AlphaAnimation, TranslationAnimation…)这些动画运行的流程解析。内容并不会去分析动画的呈现原理是什么,诸如 Matrix 这类的原理是什么,因为我也还没搞懂。本篇主要是分析当调用了 View.startAnimation()
之后,动画从开始到结束的一个运行流程是什么?
提问环节
看源码最好是带着问题去,这样比较有目的性和针对性,可以防止阅读源码时走偏和钻牛角,所以我们就先来提几个问题。
Animation 动画的扩展性很高,系统只是简单的为我们封装了几个基本的动画:平移、旋转、透明度、缩放等等,感兴趣的可以去看看这几个动画的源码,它们都是继承自 Animation 类,然后实现了 applyTransformation() 方法,在这个方法里通过 Transformation 和 Matrix 实现各种各样炫酷的动画,所以,如果想要做出炫酷的动画效果,这些还是需要去搞懂的。
目前我也还没搞懂,能力有限,所以优先分析动画的一个运行流程。
首先看看 Animation 动画的基本用法:
我们要使用一个 View 动画时,一般都是先 new 一个动画,然后配置各种参数,最后调用动画要作用到的那个 View 的 startAnimation(), 将动画实例作为参数传进去,接下去就可以看到动画运行的效果了。
那么,问题来了:
Q1:不知道大伙想过没有,当调用了 View.startAnimation() 之后,动画是马上就执行了么?
Q2:假如动画持续时间 300ms,当调用了 View.startAniamtion() 之后,又发起了一次界面刷新的操作,那么界面的刷新是在 300ms 之后也就是动画执行完毕之后才执行的,还是在动画执行过程中界面刷新操作就执行了呢?
我们都知道,applyTransformation() 这个方法是动画生效的地方,这个方法被回调时参数会传进来当前动画的进度(0.0 ——— 1.0)。就像数学上的画曲线,当给的点越多时画的曲线越光滑,同样当这个方法被回调越多次时,动画的效果越流畅。
比如一个从 0 放大到 1280 的 View 放大动画,如果这过程该方法只回调 3 次的话,那么每次的跨度就会很大,比如 0 —— 600 —— 1280,那么这个动画效果看起来就会很突兀;相反,如果这过程该方法回调了几十次的话,那么每次跨度可能就只有 100,这样一来动画效果看起来就会很流畅。
相信大伙也都有过在 applyTransformation() 里打日志来查看当前的动画进度,有时打出的日志有十几条,有时却又有几十条。
那么我们的问题就来了:
Q3:applyTransformation() 这个方法的回调次数是根据什么来决定的?
好了,本篇就是主要讲解这三个问题,这三个问题搞明白的话,以后碰到动画卡顿的时候就懂得如何去分析、定位丢帧的地方了,找到丢帧的问题所在后离解决问题也就不远了。
源码分析
ps:本篇分析的源码全都基于 android-25 版本。以下源码均采用截图方式,每张图最上面是类名+方法名,大伙想自己过一遍的时候,如果不清楚方法属于哪个类的可以在每张图最上面查看。
View.startAnimation()
刚开始接触源码分析可能不清楚该从哪入手,建议可以从我们使用它的地方来 startAnimation()
:
代码不多,调用了四个方法,那么一个个跟进去看看,先是 setStartTime()
:
所以这里只是对一些变量进行赋值,并没有运行动画