Android 属性动画 源码解析 深入了解其内部实现

719 查看

1、概述

Android中想做很炫酷的动画效果,相信在很多时候你都可以选择使用属性动画,关于属性动画如何使用,我们已经很详细的写过两篇博客讲解。如果你还不了解,请参考:

Android 属性动画(Property Animation) 完全解析 (上)

Android 属性动画(Property Animation) 完全解析 (下)

本篇博客将分析属性动画的实现源码,带你深入的了解Android属性动画的内部实现机制。如果你经常用属性动画,但又一直没有去查看其源码实现,没关系,请往下看。

2、分析前的猜想

在源码分析之前,我们需要有一个明确的思路,例如:源码的入口的选择、甚至对其实现进行简单的猜测,源码分析相当于一个验证的过程,带着一个目标去看源码,这样的话,分析和理解起来更为方便。

对于实现属性动画,最常用的类就是ObjectAnimator了,只需要简单的设置目标view,属性,以及目标值等必要属性,调用一下start();我们的动画就完成了。

类似如下代码:

上述代码很好理解吧,设置动画作用的view,作用的属性,动画开始、结束、以及中间的任意个属性值;

然后是设置插值器,当然了插值器这个词比较难理解,我要是说例如:AccelerateInterpolator、LinearInterpolator

然后设置估值算法,这个看名字挺高端,其实内部实现尤其简单:  return (int)(startInt + fraction * (endValue – startInt)); 开始值,加上当前的属性改变的百分比*(结束-开始)

当然了,这个百分比是fraction ,其实就是上面的插值器算出来的。比如线性插值器:fraction 值就是currentTime – mStartTime) / mDuration,动画的运行时间/总设置时间。

然后是设置动画事件,

最后start()。

好了,现在我想问个问题,根据上面这些参数,如果我要你设计个属性动画框架,你怎么做?

这个嘛,好整,拿到上述参数之后,start()中,开启一个定时器,去执行一个任务;在任务内部,根据Interpolator计算出来的fraction,交给Evaluator,得到属性当前应该设置的值,然后反射设置tagert的指定属性,ok,奏事这么简单。嗯,大体上应该就是这样,当然了,源码的实现肯定复杂很多,但是万变不离其宗,所以接下来的源码阅读,就是去验证我们的这个答案。

3、源码分析

好了,猜想完了,我们就得进入验证阶段了~~

那么,我们源码的入口就是上述代码了,不过貌似上述代码调用了好几个方法,but,我觉得start之前的代码,无法是初始化实例,设置一些成员变量。

首先我们看ofInt,这里为了简单,我们的ofInt中的values参数,默认就一个,类似 .ofInt(view, “translationX”, 300) ;

1、ofInt

首先调用ObjectAnimator的构造方法传入了一个target和propName,估计就是创建对象,然后旧路下target和propName,简单看下

记录完成target,propName以后,调用setIntValues

可以看到,把我们的propName,和values传入到了一个PropertyValuesHolder的ofInt方法中,去构造一个PropertyValuesHolder对象,这个对象是干什么的呢?

从字面上看,是保存view在动画期间的属性和值,记住是动画期间的。继续往下看:

可以看到在IntPropertyValuesHolder内部存储了我们的propertyName;,然后又调用了setIntValues,存储了我们的mValueType ,此外还存了一个mIntKeyframeSet。

这里又出现一个新名词,叫做mKeyframeSet,这个是由 KeyframeSet.ofInt(values);得到的。

那么这个KeyframeSet是什么呢?单纯的理解是,Keyframe的集合,而Keyframe叫做关键帧,为一个动画保存time/value(时间与值)对。

那么我们去看看它是如何通过KeyframeSet.ofInt(values);去构造与保存的: