动画的实现原理分析

最近在准备面试,不经意间看到了动画,这里想对动画做一个比较全面与深入的分析,自己也加深一下印象。那么从最先的Questions开始:

  1. Android中动画分为哪几类?
  2. 说说属性动画的实现原理
  3. view动画与属性动画之间的区别
  4. OOM与内存泄露问题
  5. activity与fragment动画
  6. 插值器


先定个基调:所谓的动画只是 不同时刻不同的画面重叠在一起,随着时间的推移给人产生了一种画面在动的感觉,其实质是在不同的时刻对应不同的画面。回到安卓中的定义是:通过 ChoreOgrapher接收 VSYNC信号来计算相应对象的对应属性,然后通过invalidate来绘制对应的画面,从而实现了动画的效果。至于 ChoreOgrapher 我会在另一篇文章单独出来分析分析。不要忘了, 所有的这一切 invalidate 才是幕后那个默默的付出者。


有了这个基调我们首先来说说Android中动画的分类

在Android 3.0之前,只存在一种动画,叫做view动画,view动画中细分为  帧动画 (Frame)与 补间动画(tween Animation),而在3.0之后添加了一种 属性动画 。


帧动画没什么好说的,就是每刷一帧展示一张图片,使用方式是写在xml文件中,唯一值得说的只是帧动画使用的图片不能太多且图片不能太大,否则容易出现内存溢出(OOM),具体使用可以看看这篇文章:Android 逐帧动画:关于 逐帧动画 的使用都在这里了!

接下来来说说Tween Animation 补间动画

补间动画只能作用于View,并且只能作用于部分的属性,类似于平移,缩放,旋转,以及透明度。对应的是安卓中已经定义的四种类型:

  • 平移:TranslateAnimation
  • 缩放:ScaleAnimation
  • 旋转:RotateAnimation
  • 透明度:AlphaAnimation


动画中一些重要的元素列一下:

  1. 总共有几个动画需要执行
  2. 每个动画要执行的起始跟最终状态
  3. 每个动画执行的时间与延时执行的时间
  4. 每个动画所使用到的插值器
  5. 动画是否重复
  6. 动画重复的类型等

如果有多个动画一起执行可能会用到AnimationSet

具体使用我就不在这里写了,有需要的可以看看这篇文章:Android 动画:手把手教你使用 补间动画

这里先说一个结论: 补间动画不改变view的属性,图形的 位移,缩放,旋转经常用到的就是 Matrix(矩阵)来表达,但是 透明度的变化矩阵是做不到的,所以Animation(子类)类中最终也提供了 getTransformation的实现, 这个方法用来获取某一时刻属性的变化值。从这个角度来讲,补间动画其实就是 矩阵与透明度的变化


我们来分析分析补间动画的执行过程:

1.调用view的startAnimation方法来设置动画并标记脏区域调用invalidate来通知ViewRootImp进行重绘

2.ViewRootImp通过一系列的坐标转换将脏区域保存,并开始走View的三大流程(由于布局未发生改变所以只会走重绘步骤)

3.ViewGroup调用drawChild方法,drawChild会调用view中带三个参数的draw方法

4.在draw方法中,会调用applyLegacyAnimation来判断当前的动画是否执行完毕,如果没有执行完毕则需要调用invalidate重新进行下一次的绘制 

5.在Animation的getTransformation中,通过动画的初始值,结束时间,以及插值器计算当前动画的进度

6.在各个Animation子类的 applyTransformation中实现最终属性的比方位移,旋转角度,透明度,以及缩放比例的值的计算,并将计算的值存到ViewGroup子View的Transformation中。

7.拿到变换的数据之后,位移,缩放,旋转通过一个3*3的矩阵变换,最终生成一张bitmap显示出来,而透明度,则通过设置layer的透明度比例来实现。


总结:补间动画的实现不改变View的属性,无论是位移缩放旋转透明度的变化,其实际的View是没有发生任何改变的, 所以这也 就解释了为何设置在View上的点击事件没有随动画的改变而改变



下面来聊聊属性动画(animator):

属性动画与view动画的实现方式有点不一样,具体不一样在哪里,我们细细来分析:

 先说说属性动画实现的流程:


  1. 通过of方法创建PropertyValuesHolder,并设置变化值的区间范围
  2. 调用start启动动画,这个步骤是通过AnimationHandler将一个ChoreOgrapher.FrameCallback post到ChoreOgrapher中去监听VSYNC信号的到来,同时将AnimationHandler.AnimationFrameCallback添加到列表中,后面会通过这个列表的长度是否为0来判断动画是否结束。
  3. 当VSYNC信号到来是执行ChoreOgrapher.FrameCallback,当步骤二中的列表size大于0,表示动画尚未结束,继续步骤二 。代码如下:                           

  4. 这一步骤会调用ValueAnimator中的doAimationFrame方法,如果当前动画暂停,或者动画已经执行结束,会调用removeAnimationCallback将当前的callback赋空值,然后从步骤1中的列表移除掉,否则执行步骤5
  5. 通过开始时间,结束时间,延迟启动时间以及插值器计算当前动画应该所处的状态(百分比),并通过这个fraction(百分比)调用对应的PorpertyValuesHolder去计算属性的值。
  6. 计算属性的之后先通过属性名获得对应属性的getter与setter方法,并通过反射,将计算后的属性值设置到对象中去
  7. 属性变化之后会重新走View的三大流程


总结:属性动画依赖的是ChoreOgrapher,在每次三大流程开始之前会将对应时间段的属性设置完毕






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值