属性动画简单分析(一)
来源:互联网 发布:forespider爬虫软件 编辑:程序博客网 时间:2024/05/28 22:13
《在《线性贝塞尔曲线的简单说明》这篇博文中简单介绍了贝塞尔曲线在android里简单的应用,文章开头说这些有什么用呢?跟属性动画完全不搭边啊!昨天晚上自己仔细研究了下属性动画KeyFrame的源码,发现基本的算法跟《贝塞尔曲线简单说明》这篇博客写的差不多,所以对有关具体算法的说明还请读者参考《贝塞尔曲线的简单说明》这篇博文。
至于为什么会想到阅读属性动画的源码,其实原因也很简单:在自己重构代码的过程中,总感觉自己项目架构写的不是很优雅,扩展性不是很强,而且结构混乱,就想分析分析这个源码看看别人是怎么组织项目架构的,以前研究Gson的源码也是如此原因。通过分析属性动画的源码,确实也体会到了不少的东西,甚至有的没办法用语言描述出来。扯得有点多了,闲言少叙,书归正传.
属性动画的核心原理也很简单:
1)传入你要操作的对象,即目标对象,也即是Target.
2) 传入你要操作的属性propertyName
3) 通过反射机制,不断的调用Target对象的setPropertyName方法:当然setPropertyName方法的具体实现完全由咱们IT Monkey自己定制。
简单原理叙说完毕,那么就开始开车了:
ObjectAnimation类本身提供了三种构造函数来进行对象的构建,默认函数为public,其余的两个是private的,默认的构造函数在这里暂且不提。如果想要创建ObjectAnimation对象的话,其内部提供了几个静态方法来创建:比如ofObject,ofInt等,鉴于本人在开发中的使用情况就从ofObject这个方法开始说起:
public static ObjectAnimator ofObject(Object target, String propertyName, TypeEvaluator<?> evaluator, Object... values) { //调用私有构造器 ObjectAnimator anim = new ObjectAnimator(target, propertyName); //保存属性动画客户端传来的序列值 anim.setObjectValues(values); //设置估值器 anim.setEvaluator(evaluator); return anim; }
1)调用了私有构造器来初始化ObjectAnimator 对象,这个构造器也很简单,就是ofObject参数中传入的target和propertyName分别赋予ObjectAnimator的mTarget和mPropertyName,并将mInitialized这个表示是否初始化完成的boolean变量设置为false,该变量的作用就是用来标记动画是否可以开始!
2)既然propertyName和target都已经复制完毕,那么很简单接下来就是处理ofObject方法传来的values了:交给setObjectValues处理
public void setObjectValues(Object... values) { if (mValues == null || mValues.length == 0) { if (mProperty != null) { //省略部分代码 } else {//调用的此处 //将values序列交给 PropertyValuesHolder的ofObject处理 setValues(PropertyValuesHolder.ofObject(mPropertyName, (TypeEvaluator) null, values)); } } else { super.setObjectValues(values); } }
最终会发现传入的values序列值交给了PropertyValuesHolder的静态方法ofObject,通过该方法的处理,生成了PropertyValuesHolder对象,作为参数传入了ObjectAnmiaton对象的setValues方法。为了文章的连贯性,把PropertyValuesHolder的说明暂时阁下,先简单看一个setValues方法:
//方法参数是PropertyValuesHolder,说明你可以用ObjectAnmation的setValues方法传入若干个PropertyValuesHolder对象public void setValues(PropertyValuesHolder... values) { int numValues = values.length; mValues = values; //key:属性名,value:属性对应的PropertyValuesHolder mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues); //把传入的PropertyValuesHolder对象添加到mValuesMap中 for (int i = 0; i < numValues; ++i) { PropertyValuesHolder valuesHolder = (PropertyValuesHolder) values[i]; mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder); } // New property/values/target should cause re-initialization prior to // starting mInitialized = false; }
setValues方法很简单,具体来说就是做了如下工作:
1)将方法参数复制给ObjectAnimation对象的PropertyValuesHolder mValues[]数组;
2)将PropertyValuesHolder对象数组添加到以propertyName为key,以PropertyValuesHolder对象为value的map中。
到此为止,从流程上来说ObjectAnimation的ofObject方法已经说名完毕,但是根据前文的说明,ofObject方法传入的values是交给了PropertyValuesHolder,我们现在看看PropertyValuesHolder这个类具体干了什么好事儿。
PropertyValuesHolder:顾名思义,就是持有propertyName所对应的values序列值的对象,一个PropertyValuesHolder对象持有一个propertyName及其对应的values序列,只不过这个序列是通过KeyFramseSet持有,前面通过ofObject将propertyName和values对象传入进来:
public static PropertyValuesHolder ofObject(String propertyName, @SuppressWarnings("rawtypes") TypeEvaluator evaluator, Object... values) { //设置给propertyName方法 PropertyValuesHolder pvh = new PropertyValuesHolder(propertyName); //把vlaue方法最终传给PVH pvh.setObjectValues(values); pvh.setEvaluator(evaluator); return pvh; }
values交给setObjectValues来处理:
public void setObjectValues(Object... values) { mValueType = values[0].getClass(); //把values最终传给mKeyFrameSet方法 mKeyframeSet = KeyframeSet.ofObject(values); }
通过代码可知最终values被传到了KeyFrameSet的ofObject里面,经过处理生成一个KeyFrameSet对象:
public static KeyframeSet ofObject(Object... values) { int numKeyframes = values.length; //ObjectKeyframe最少两帧动画 ObjectKeyframe keyframes[] = new ObjectKeyframe[Math.max(numKeyframes, 2)]; if (numKeyframes == 1) {//如果传过来的是一个值 //动画第一帧其其实fraaction=0,该帧对应的值是0 keyframes[0] = (ObjectKeyframe) Keyframe.ofObject(0f); //动画第二个fraction=1,该帧对应的值就是你传入的那个值 keyframes[1] = (ObjectKeyframe) Keyframe.ofObject(1f, values[0]); } else { keyframes[0] = (ObjectKeyframe) Keyframe.ofObject(0f, values[0]); //把传入的其余的值根据传入的序列对i/(n-1)-->values[i]进行映射 for (int i = 1; i < numKeyframes; ++i) { keyframes[i] = (ObjectKeyframe) Keyframe.ofObject((float) i / (numKeyframes - 1), values[i]); } } //返回帧集合:传入多少个值就传多少个有多少帧 return new KeyframeSet(keyframes); } public KeyframeSet(Keyframe... keyframes) { mNumKeyframes = keyframes.length; //帧序列集合 mKeyframes = new ArrayList<Keyframe>(); mKeyframes.addAll(Arrays.asList(keyframes)); //记录第一帧 mFirstKeyframe = mKeyframes.get(0); //记录最后一帧 mLastKeyframe = mKeyframes.get(mNumKeyframes - 1); mInterpolator = mLastKeyframe.getInterpolator(); }
上面的算法很简单,跟《线性贝塞尔曲线简单说明》这篇博文算法思路完全一样!!!在这里稍微总结一下:
1)客户端通过ObjectAnimation的ofObject()方法传入多少个value(一个除外)就有多少个KeyFrame对象,每个KeyFrame对象持有与KeyFrame对象创建顺序对应的value
2)KeyFrame有一个mFraction变量,该变量的初始化计算算法为:
mFraction = (float)i/(values.length-1)
简单的用图表来表示values和KeyFrame之间的关系就是:
到此为止,算是完成了对ObjectAnimation对象的初始化工作,再次简单梳理下,分成大致几个点:
1)通过ObjectAnimation的ofXXX方法,设置propertyName和values。
2)将propertyName和values封装成PropertyValueHolder对象:每个PropertyValueHolder对象持有values组成的帧序列对象KeyFrameSet对象;
3)将步骤2创建的PropertyValueHolder对象用ObjectAnimation的mValues 数组保存起来;然后将propertyName作为key,PropertyValueHolder作为value保存到mValuesMap中。
最终简单的创建骨架可以用如下图来作为总结:
总体上,ObjectAnimation的创建流程简单分析完毕,至于属性动画的执行流程,篇幅有限,下篇博文《属性动画的简单分析二》再分析,不足之处欢迎批评指正。
- 属性动画简单分析(一)
- 属性动画简单分析
- 属性动画简单说明前篇(一)
- Android属性动画ValueAnimator源码简单分析
- Android属性动画ObjectAnimator源码简单分析
- Android属性动画AnimatorSet源码简单分析
- Android属性动画ObjectAnimator源码简单分析
- 浅谈属性动画的简单使用(一)
- 动画概述 一,创建一个简单的属性动画
- Anroid动画总结一:属性动画(Property)简单应用
- Android动画机制与使用技巧(一)属性动画分析
- Android动画--属性动画总结(一)
- Android动画机制-属性动画(一)
- Android 属性动画 (一)
- Android 属性动画(一)
- Android动画学习-视图动画&属性动画(一)
- android动画基础(一) View动画和属性动画
- Android属性动画-Property Animation(一) 原理分析
- Centos6.8安装Nginx
- 使用cxf,spring,mybatis框架完成restful风格的webservice服务
- STM32学习三:下载标准外设库(Standard Peripherals Library )
- SpringMVC之web.xml解读
- java等额本金与等额本息
- 属性动画简单分析(一)
- 更新gcc并切换
- NIO 读写
- centos mysql 1045 错误
- UEditor上传图片到项目外部目录
- QT检测系统语言环境自动切换语言
- left join加上where条件的困惑,(left join 无用 / 无效 )
- selenium-python
- Jersey