Android动画分类:
1.Tween Animation:补间动画
补间动画分类:a.Alpha:渐变透明度的动画
b.Scale:渐变尺寸缩放动画c.Translate:位置移动动画 d.Rotate:旋转动画他们共有属性:(1)Duration:动画持续时间(单位:毫秒) (2)fillAfter:设置为true,动画转化在动画结束后被应用 (3)fillBefore:设置为true,动画转化在动画开始前被应用 (4)interpolator:动画插入器(加速、减速插入器) (5)repeatCount:动画重复次数 (6)repeatMode:顺序重复/倒序重复 (7)startOffset:动画之间的时间间隔2.Frame Animation:帧动画,将一组图片按一定的时间间隔显示出来 3.Layout Animation:布局动画 4.Property Animation:属性动画补间动画实现步骤:(1)配置文件
(/res/anim)-->alpha、Scale、Translate、rotate
以<set></set>作为根布局 (2)java代码实现加载配置文件:Animation animation=AnimationUtils.loadAnimation(context,R.anim.alpha_animation) view.startAnimation(animation);各个动画的具体实现可以到以下链接上下载看看,有详细的注释:http://download.csdn.net/detail/luck_136/9586997补间动画实现的原理:
当我们给View控件设置动画效果之后,并且保持View控件在动画结束的位置,这个时候给view控件添加点击事件我们会发现,View控件根本不会响应,而当我们先看view.startAnimation(animation)的startAnimation(animation)的源码:点击View控件原有位置,会发现点击事件被响应了。这表明,View控件的LayoutParams参数根本没有发生改变,所以Animation设置的动画只是一种假象,那么这是怎么回事呢?
/** * Start the specified animation now. * * @param animation the animation to start now */public void startAnimation(Animation animation) { animation.setStartTime(Animation.START_ON_FIRST_FRAME); // 这个方法,会给 view 自己内部设置一个 Animation 对象(内部变量为 mCurrentAnimation) setAnimation(animation); invalidateParentCaches(); // 通知 View 进行刷新界面 invalidate(true); }
我们可以看到:这里实际上是给View设置了一个animation。
再看invalidateParentCaches()的源码:
protected void invalidateParentCaches() { if (mParent instanceof View) { ((View) mParent).mPrivateFlags |= PFLAG_INVALIDATED; } }
这里是当前View的父控件,其实是通过ParentView不断的调整ChildView的画布坐标实现的。以平移动画为例。假设在动画开始时 ChildView 在 ParentView 中的初始位置在 (100,200) 处,这时 ParentView 会根据这个坐标来设置 ChildView 的画布,在 ParentView 的 dispatchDraw 中它发现 ChildView 有一个平移动画,而且当前的平移位置是 (100, 200),于是它通过调用画布的函数 traslate(100, 200) 来告诉 ChildView 在这个位置开始画,这就是动画的第一帧。如果 ParentView 发现 ChildView 有动画,就会不断的调用 invalidate() 这个函数,这样就会导致自己会不断的重画,就会不断的调用 dispatchDraw 这个函数,这样就产生了动画的后续帧,当再次进入 dispatchDraw 时,ParentView 根据平移动画产生出第二帧的平移位置 (500, 200),然后继续执行上述操作,然后产生第三帧,第四帧,直到动画播完。
父控件(ViewGroup)中dispatchDraw()源码:
只要子view可见或者子view设置了动画,那么就会对该子view调用drawChild(canvas, child, drawingTime)
这其中又涉及到两个重要的类型,Animation 和 Transformation,这两个类是实现动画的主要的类,Animation 中主要定义了动画的一些属性比如开始时间、持续时间、是否重复播放等,这个类主要有两个重要的函数:getTransformation 和 applyTransformation,在 getTransformation 中 Animation 会根据动画的属性来产生一系列的差值点,然后将这些差值点传给 applyTransformation,这个函数将根据这些点来生成不同的 Transformation,Transformation 中包含一个矩阵和 alpha 值,矩阵是用来做平移、旋转和缩放动画的,而 alpha 值是用来做 alpha 动画的(简单理解的话,alpha 动画相当于不断变换透明度或颜色来实现动画),以上面的平移矩阵为例子,当调用 dispatchDraw 时会调用 getTransformation 来得到当前的 Transformation。
这个 Transformation 中的矩阵如下:
矩阵变换图
![矩阵变换图](https://i-blog.csdnimg.cn/blog_migrate/52866f3ac75201e781effa085a8cf62f.png)
所以具体的动画只需要重载 applyTransformation 这个函数即可
用户可以定义自己的动画类,只需要继承 Animation 类,然后重载 applyTransformation 这个函数。对动画来说其行为主要靠差值点来决定的,比如,我们想开始动画是逐渐加快的或者逐渐变慢的,或者先快后慢的,或者是匀速的,这些功能的实现主要是靠差值函数来实现的,Android 提供了 一个 Interpolator 的基类,你要实现什么样的速度可以重载其函数 getInterpolation,在 Animation 的 getTransformation 中生成差值点时,会用到这个函数。
从上面的动画机制的分析可知某一个 View 的动画的绘制并不是由他自己完成的而是由它的父 view 完成,所有我们要注意上面 TextView 旋转一周的动画示例程序中动画的效果并不是由 TextView 来绘制的,而是由它的父 View 来做的。
总结:invalidate(true)实际上是调用父控件来不断的重新绘制自己, 它把动画的播放 / 绘制交给父 View 去处理而不是让子 View 本身去绘制,这种从更高的层次上去控制的方式便于把动画机制做成一个易用的框架,如果用户要在某个 view 中使用动画,只需要在 xml 描述文件或代码中指定就可以了,从而把动画的实现和 View 本身内容的绘制(象 TextView 里面的文字显示)分离开了,起到了减少耦合和提高易用性的效果。