转载请注明出处: http://blog.csdn.net/singwhatiwanna/article/details/17841165

前言

感谢你阅读本文,我坚信读完本文肯定不会让你失望的。想要做动画牛人?想要精通动画?那么本文所讲的内容都是你必须要掌握的。关于动画,我已经写了两篇博文,但是还是没有将动画描述全面,于是我写了本文,另外,我后面还会再写一篇属性动画的源码分析,通过这四篇博文,你将真正地成为动画牛人。

Android动画系列:

android动画简介

Android动画进阶—使用开源动画库nineoldandroids

Android属性动画深入分析:让你成为动画牛人

Android源码分析—属性动画的工作原理

我为什么要写这篇博文?

是分享精神,我对动画从了解到熟悉是经历了一个过程,而这一个过程是要花费时间的,也许是几天,也许是几个小时,总之没有至少若干小时的时间投入,你是无法熟悉动画的全部的。我花了大量时间来弄懂动画的整个逻辑,深知其中的辛苦,所以,我不想大家再像我这样,我想大家能够更快地熟悉并精通动画。通过本文,你将会深入了解Android动画并且从此没有动画再能难得了你。确切来说本文是深入分析属性动画,因为View动画和帧动画的功能有限也比较简单,没有太多值得分析的东西。

开篇

像设计模式一样,我们也提出一个问题来引出我们的内容。

问题:

给Button加一个动画,让这个Button的宽度从当前宽度增加到500px。

也许你会说,这很简单,用渐变动画就可以搞定,我们可以来试试,你能写出来吗?很快你就会恍然大悟,原来渐变动画根本不支持对宽度进行动画啊,没错,渐变动画只支持四种类型:平移(Translate)、旋转(Rotate)、缩放(Scale)、不透明度(Alpha)。当然你用x方向缩放(scaleX)可以让Button在x方向放大,看起来好像是宽度增加了,实际上不是,只是Button被放大了而已,而且由于只在x方向被放大,这个时候Button的背景以及上面的文本都被拉伸了,甚至有可能Button会超出屏幕。下面是效果图

上述效果显然是很差的,而且也不是真正地对宽度做动画,不过,所幸我们还有属性动画,我们用属性动画试试

看demo

    private void performAnimate() {ObjectAnimator.ofInt(mButton, "width", 500).setDuration(5000).start();}@Overridepublic void onClick(View v) {if (v == mButton) {performAnimate();}}

上述代码运行一下发现没效果,其实没效果是对的,如果你随便传递一个属性过去,轻则没动画效果,重则程序直接Crash。

下面分析下属性动画的原理:

属性动画要求动画作用的对象提供该属性的get和set方法,属性动画根据你传递的该熟悉的初始值和最终值,以动画的效果多次去调用set方法,每次传递给set方法的值都不一样,确切来说是随着时间的推移,所传递的值越来越接近最终值。总结一下,你对object的属性xxx做动画,如果想让动画生效,要同时满足两个条件:

1. object必须要提供setXxx方法,如果动画的时候没有传递初始值,那么还要提供getXxx方法,因为系统要去拿xxx属性的初始值(如果这条不满足,程序直接Crash)

2. object的setXxx对属性xxx所做的改变必须能够通过某种方法反映出来,比如会带来ui的改变啥的(如果这条不满足,动画无效果但不会Crash)

以上条件缺一不可

那么为什么我们对Button的width属性做动画没有效果?这是因为Button内部虽然提供了getWidth和setWidth方法,但是这个setWidth方法并不是改变视图的大小,它是TextView新添加的方法,View是没有这个setWidth方法的,由于Button继承了TextView,所以Button也就有了setWidth方法。下面看一下这个getWidth和setWidth方法的源码:

    /*** Makes the TextView exactly this many pixels wide.* You could do the same thing by specifying this number in the* LayoutParams.** @see #setMaxWidth(int)* @see #setMinWidth(int)* @see #getMinWidth()* @see #getMaxWidth()** @attr ref android.R.styleable#TextView_width*/@android.view.RemotableViewMethodpublic void setWidth(int pixels) {mMaxWidth = mMinWidth = pixels;mMaxWidthMode = mMinWidthMode = PIXELS;requestLayout();invalidate();}/*** Return the width of the your view.** @return The width of your view, in pixels.*/@ViewDebug.ExportedProperty(category = "layout")public final int getWidth() {return mRight - mLeft;}

从源码可以看出,getWidth的确是获取View的宽度的,而setWidth是TextView和其子类的专属方法,它的作用不是设置View的宽度,而是设置TextView的最大宽度和最小宽度的,这个和TextView的宽度不是一个东西,具体来说,TextView的宽度对应Xml中的android:layout_width属性,而TextView还有一个属性android:width,这个android:width属性就对应了TextView的setWidth方法。好吧,我承认我的这段描述有点混乱,但事情的确是这个样子的,而且我目前还没发现这个android:width属性有啥重要的用途,感觉好像没用似的,这里就不深究了,不然就偏离主题了。总之,TextView和Button的setWidth和getWidth干的不是同一件事情,通过setWidth无法改变控件的宽度,所以对width做属性动画没有效果,对应于属性动画的两个条件来说,本例中动画不生效的原因是只满足了条件1未满足条件2。

针对上述问题,Google告诉我们有3中解决方法:

1. 给你的对象加上get和set方法,如果你有权限的话

2. 用一个类来包装原始对象,间接为其提供get和set方法

3. 采用ValueAnimator,监听动画过程,自己实现属性的改变

看起来有点抽象,不过不用担心,下面我会一一介绍。

对任何属性做动画

针对上面提出的三种解决方法,这里会给出具体的介绍:

给你的对象加上get和set方法,如果你有权限的话

这个的意思很好理解,如果你有权限的话,加上get和set就搞定了,但是很多时候我们没权限去这么做,比如本文开头所提到的问题,你无法给Button加上一个合乎要求的setWidth方法,因为这是Android SDK内部实现的。这个方法最简单,但是往往是不可行的,这里就不对其进行更多分析了。

用一个类来包装原始对象,间接为其提供get和set方法

这是一个很有用的解决方法,是我最喜欢用的,因为用起来很方便,也很好理解,下面将通过一个具体的例子来介绍它

    private void performAnimate() {ViewWrapper wrapper = new ViewWrapper(mButton);ObjectAnimator.ofInt(wrapper, "width", 500).setDuration(5000).start();}@Overridepublic void onClick(View v) {if (v == mButton) {performAnimate();}}private static class ViewWrapper {private View mTarget;public ViewWrapper(View target) {mTarget = target;}public int getWidth() {return mTarget.getLayoutParams().width;}public void setWidth(int width) {mTarget.getLayoutParams().width = width;mTarget.requestLayout();}}

上述代码5s内让Button的宽度增加到500px,为了达到这个效果,我们提供了ViewWrapper类专门用于包装View,具体到本例是包装Button,然后我们对ViewWrapper的width熟悉做动画,并且在setWidth方法中修改其内部的target的宽度,而target实际上就是我们包装的Button,这样一个间接属性动画就搞定了。上述代码同样适用于一个对象的其他属性。下面看效果

ok,效果达到了,真正实现了对宽度做动画。

采用ValueAnimator,监听动画过程,自己实现属性的改变

首先说说啥是ValueAnimator,ValueAnimator本身不作用于任何对象,也就是说直接使用它没有任何动画效果。它可以对一个值做动画,然后我们可以监听其动画过程,在动画过程中修改我们的对象的属性值,这样也就相当于我们的对象做了动画。还是不太明白?没关系,下面用例子说明

    private void performAnimate(final View target, final int start, final int end) {ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 100);valueAnimator.addUpdateListener(new AnimatorUpdateListener() {//持有一个IntEvaluator对象,方便下面估值的时候使用private IntEvaluator mEvaluator = new IntEvaluator();@Overridepublic void onAnimationUpdate(ValueAnimator animator) {//获得当前动画的进度值,整型,1-100之间int currentValue = (Integer)animator.getAnimatedValue();Log.d(TAG, "current value: " + currentValue);//计算当前进度占整个动画过程的比例,浮点型,0-1之间float fraction = currentValue / 100f;//这里我偷懒了,不过有现成的干吗不用呢//直接调用整型估值器通过比例计算出宽度,然后再设给Buttontarget.getLayoutParams().width = mEvaluator.evaluate(fraction, start, end);target.requestLayout();}});valueAnimator.setDuration(5000).start();}@Overridepublic void onClick(View v) {if (v == mButton) {performAnimate(mButton, mButton.getWidth(), 500);}}

上述代码的动画效果图和采用ViewWrapper是一样的,请参看上图。关于这个ValueAnimator我要再说一下,拿上例来说,它会在5000ms内将一个数从1变到100,然后动画的每一帧会回调onAnimationUpdate方法,在这个方法里,我们可以获取当前的值(1-100),根据当前值所占的比例(当前值/100),我们可以计算出Button现在的宽度应该是多少,比如时间过了一半,当前值是50,比例为0.5,假设Button的起始宽度是100px,最终宽度是500px,那么Button增加的宽度也应该占总增加宽度的一半,总增加宽度是500-100=400,所以这个时候Button应该增加宽度400*0.5=200,那么当前Button的宽度应该为初始宽度+ 增加宽度(100+200=300)。上述计算过程很简单,其实它就是整型估值器IntEvaluator的内部实现,所有我们不用自己写了,直接用吧。

写在后面的话

到此为止,本文的分析基本完成,有几点是我想再说一下的。

1.View动画(渐变动画)的功能是有限的,大家可以尝试使用属性动画

2.为了在各种安卓版本上使用属性动画,你需要采用nineoldandroids,它是GitHub开源项目,jar包和源码都可以在网上下到,如果下不到jar包,我可以发给大家

3.再复杂的动画都是简单动画的合理组合,再加上本文介绍的方法,可以对任何属性作用动画效果,也就是说你几乎可以做出任何动画

4.属性动画中的插值器(Interpolator)和估值器(TypeEvaluator)很重要,它是实现非匀速动画的重要手段,你应该试着搞懂它,最好你还能够自定义它们

5.如果你能把我这个动画系列博文都看一遍并且理解它,我认为你对动画绝对算得上精通,而且我不认为有面试官能够在动画上问倒你

Android属性动画深入分析:让你成为动画牛人相关推荐

  1. 《Android开发艺术探索》读书笔记 (7) 第7章 Android动画深入分析

    本节和<Android群英传>中的第七章Android动画机制与使用技巧有关系,建议先阅读该章的总结 第7章 Android动画深入分析 7.1 View动画 (1)android动画分为 ...

  2. Android开发艺术探索——第七章:Android动画深入分析

    Android开发艺术探索--第七章:Android动画深入分析 Android的动画可以分成三种,view动画,帧动画,还有属性动画,其实帧动画也是属于view动画的一种,,只不过他和传统的平移之类 ...

  3. 秒懂Android属性动画

    自从Android3.0 版本加入属性动画后,在平时的开发中多多少少也使用了,但是从来没有对其做一个系统的分析和总结,最近刚好有点时间,来对这个话题做一个分析和总结. 概述 Android动画体系 引 ...

  4. Android 属性动画(Property Animation) ObjectAnimator的介绍

    先说下属性动画与视图动画的区别: 视图动画系统仅提供为 View 对象添加动画效果的功能,因此,如果您想为非 对象添加动画效果,则必须实现自己的代码才能做到.视图动画系统也存在一些限制,因为它仅公开 ...

  5. Android 属性动画(Property Animation) ValueAnimator 的介绍

    先说下属性动画与视图动画的区别: 视图动画系统仅提供为 View 对象添加动画效果的功能,因此,如果您想为非 对象添加动画效果,则必须实现自己的代码才能做到.视图动画系统也存在一些限制,因为它仅公开 ...

  6. Android属性动画源代码解析(超详细)

    本文假定你已经对属性动画有了一定的了解,至少使用过属性动画.下面我们就从属性动画最简单的使用开始. ObjectAnimator.ofInt(target,propName,values[]).set ...

  7. android动画封装,Android属性动画封装,快速构建动画

    Android实现动画效果的方式主要有帧动画.补间动画.属性动画.关于安桌动画的基础知识可以查看这篇文章Android属性动画完全解析 这里我要讲的是如何快速构建出一个动画效果,如下图: 如果我们用属 ...

  8. android+动画队列,Android属性动画详解

    前言 属性动画是Android 3.0(API 11)新加入的动画框架,属性动画弥补了视图动画的很多短板,因此已经成为大多数动画场景的首选框架. 目录 目录 1. 属性动画出现的原因 在属性动画出现以 ...

  9. android 属性动画失败,AndroidAnimationExercise

    AndroidAnimationExercise 这是一个关于Android中各种View的集合,里面包含自己日常开发和博客总结中的代码. 主要内容是Android动画.Android自定义View ...

最新文章

  1. 对于HTML表单输入字段,disabled =“ disabled”和readonly =“ readonly”有什么区别?
  2. 又一个智商税产品“路由器防辐射笼”,信号都没了,还能火爆全网...
  3. bzoj 4012: [HNOI2015]开店
  4. python—时间复杂度
  5. 金泰联限量稳定虚拟主机赞助计划
  6. IAR不进调试界面DEBUG界面,直接烧写程序。完美解决,还可以添加到工具栏
  7. windows7+tomcat7+nginx1.11.3 +memcached
  8. Codewars-Regex Password Validation(正则检验密码格式)
  9. linux C语言调用Intel处理器CPUID指令的实例
  10. VSAN效能监控利器-VSAN Observer
  11. 23、jQuery九类选择器/jQuery常用Method-API/jQuery常用Event-API
  12. nodejs+express中设置登录拦截器
  13. 浅析引用类型和基本类型的内存比较
  14. 软件dfmea_fmea软件|失效模式与效应分析(fmea)下载 v03.01.13.0中文版 - 121下载站
  15. python使用gps设备
  16. linux如何停止命令运行,linux的停止命令
  17. sqoop:File does not exist:
  18. Jfrog:烂泥蛙安装
  19. 坚持是一种孤独,开发就是这么坑!
  20. Mybatis中的<![CDATA[ ]]>作用

热门文章

  1. 大数据学习-大数据环境配置
  2. jenkins构建UNSTABLE原因及解决方案一二三四五(不断更新中。。。)
  3. vue项目部署上线总流程
  4. linux命令行安装java_如何在Linux平台命令行环境下安装Java1.6
  5. 论文笔记——Using Progressive Context Encoders for Anomaly Detection in Digital Pathology Images
  6. java8 metaspacesize_Metaspace 之三--jdk8 Metaspace 调优
  7. one more DDH assumption
  8. 在div 鼠标悬停时改变滚定条样式
  9. swift 命名空间
  10. linux下压缩文件解压文件,linux下 解压和压缩文件 rar文件解压