一、前言
Android动画包含三种:补间动画(Tween Animation),帧动画(Frame Animation),属性动画 (Property Animation)。其中属性动画是从Android 3.0之后加入的。
本文着重介绍三种动画的实现原理,阅读本文的前提是应该可以简单的使用上述三种动画。
如不熟悉可以参考以下链接,
补间动画:http://www.cnblogs.com/whoislcj/p/5730520.html
逐帧动画:http://www.cnblogs.com/whoislcj/p/5733740.html
属性动画:http://www.cnblogs.com/whoislcj/p/5738478.html
二、补间动画原理(Tween Animation)
原理:在绘制的过程中,尝试获取动画在当前时刻的变换,然后应用到view的绘制中。
 
说明:
绘制是显示view所必不可少的过程,通过view的draw方法可以看到绘制的流程。
查看View.java的源码,可以发现有两个draw方法,一个有一个参数,一个有三个参数。分别是
public void draw(Canvas canvas)
boolean draw(Canvas canvas, ViewGroup parent, long drawingTime)

其中一个参数的draw方法是具体的绘制过程(绘制背景、绘制内容、绘制前景...)
含有三个参数的draw方法是由父布局调用的(ViewGroup.drawChild),因为Android绘制的过程是从根布局开始,
子View是否能够绘制由父布局决定。这个方法就是提前处理绘制的位置的地方,补间动画也是在此处进行了处理以实现动画的效果。
先举一个例子,
Animation translateAnimation = new TranslateAnimation(0, 100, 0, 0);

translateAnimation.setDuration(500);
translateAnimation.setInterpolator(new AccelerateInterpolator());

translateAnimation.setFillAfter(true);//设置动画结束后保持当前的位置(即不返回到动画开始前的位置)

imageView.startAnimation(translateAnimation);
一个动画重要的东西就四个部分,开始时间,结束时间,做什么,如何做。
上述是一个imageView在x方向移动的动画,可以看到它符合上面所说的四个部分,
做什么:沿x方向移动100
如何做:直线且不断加速
开始时间:startAnimtion调用的那一刻
结束时间: 开始时间+500
从上面也大致了解到补间动画的框架是通过先建立一个Animation对象并对其设置一些属性,然后将它与一个view建立关联,
最后这个view可以执行这个动画。
由此我们开始分析Animation的源码(基于Android 6.0):
Animation及相关类的源码在frameworks/base/core/java/android/view/animation包中。
其中Animation类是一个抽象类,虽然它没有抽象方法,但是它有一个空方法
protected void applyTransformation(float interpolatedTime, Transformation t)
可以看到,它有两个参数,第一个参数是 interpolatedTime 它代表插值后的时间,第二个参数是Transformation类的实例
Transformation是一个实体类,它主要的内容是透明度和一个矩阵。
所以子类实现了applyTransformation方法后可以针对插值时间来对Transformation做一定的操作来实现变化。
同时可以看到applyTransformation是在Animtaion的getTransformation中调用的,
public boolean getTransformation(long currentTime, Transformation outTransformation)
其中currentTime作为一个参数,虽然期望的是当前时间,但是不是用还是由调用者决定。
第二个参数目的是调用者传进来作为收集变化信息
此方法除了调用回调(开始,结束,重复),重点是调用applyTransformation前的这一句
final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime);
插值器的目的是为了将控制动画速度的过程抽离出来,它是通过改变时间来改变最终效果。
normalizedTime 的范围是0.0f~1.0f
但是interpolatedTime可以超出这个范围
所以在实现applyTransformation的时候需要考虑插值后的时间这个范围之外的情况。
下面以TranslateAnimation和AccelerateInterpolator来说明是如何实现的
可以知道
TranslateAnimation主要实现applyTransformation方法
AccelerateInterpolator主要实现getInterpolation方法
 
下面是两个方法的源码:
protected void applyTransformation(float interpolatedTime, Transformation t) {
float dx = mFromXDelta;
float dy = mFromYDelta;
if (mFromXDelta != mToXDelta) {
dx = mFromXDelta + ((mToXDelta - mFromXDelta) * interpolatedTime);
}
if (mFromYDelta != mToYDelta) {
dy = mFromYDelta + ((mToYDelta - mFromYDelta) * interpolatedTime);
}
  t.getMatrix().setTranslate(dx, dy);//改变了Transformation的矩阵偏移
}
public float getInterpolation(float input) {
if (mFactor == 1.0f) {
return input * input; //输入0.5 返回0.25
} else {
return (float)Math.pow(input, mDoubleFactor);
}
}
如此一来,动画的变化,就隐藏在Transformation之中了。
既然已经知道了如何变化,现在就需要系统使用这种变化即应用到绘制中了。
移步到View.java之中的draw(--,--,--)方法,
其中applyLegacyAnimation方法是用来获取变换的,
其中有两个部分需要注意
a.getTransformation(drawingTime, invalidationTransform, 1f);
a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region,
invalidationTransform);
第一个就是获取变换,第二个是获取绘制无效区域。
其实这个无效区域是绘制后的无效区域,因为很有可能需要下次绘制(保证动画连续性)。
而view在draw之中
if (transformToApply != null) {
if (concatMatrix) {
if (drawingWithRenderNode) {
renderNode.setAnimationMatrix(transformToApply.getMatrix());
} else {
// Undo the scroll translation, apply the transformation matrix,
// then redo the scroll translate to get the correct result.
canvas.translate(-transX, -transY);
canvas.concat(transformToApply.getMatrix());
canvas.translate(transX, transY);
}
parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION;
}
float transformAlpha = transformToApply.getAlpha();
if (transformAlpha < 1) {
alpha *= transformAlpha;
parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION;
}
} 
分别从硬件加速和软件绘制上 对canvas进行矩阵变换.
除了TranslateAnimation,系统还有AlphaAnimation和ClipRectAnimation可供选择.
三、逐帧动画原理(Frame Animation)
原理:使用了Choreographer机制
AnimationDrawable类是一个实现了逐帧动画的类,可以看出,它只用来进行图片的动态切换.
AnimationDrawable类源码在frameworks/base/graphics/java/android/graphics/drawable/中
public class AnimationDrawable extends DrawableContainer implements Runnable, Animatable
首先看到AnimationDrawable继承了DrawableContainer,因为DrawableContainer是一个drawable的容器,可以保存多个图片
同时,实现了Runnable接口,重写了run方法
根据源码中的start方法,它调用了setFrame方法,方法内部最重要的调用就是调用了
scheduleSelf(this, SystemClock.uptimeMillis() + mAnimationState.mDurations[frame]);
上述方法实现是在Drawable类实现的
public void scheduleSelf(Runnable what, long when) {
final Callback callback = getCallback();
if (callback != null) {
callback.scheduleDrawable(this, what, when);
}
}
其中callback一般是drawable相关联的view.
可以看出,它接着回调了view的scheduleDrawable方法
而这个方法最终会
mAttachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed(
Choreographer.CALLBACK_ANIMATION, what, who,
Choreographer.subtractFrameDelay(delay));
来实现delay后,可以绘制下一帧的效果.
因为AnimationDrawable所实现了runnable接口的run方法就是执行nextFrame.
同时,AnimatedStateListDrawable和AnimatedVectorDrawable和AnimatedRotateDrawable(隐藏)
都是具备一定的动画效果
其中,AnimatedStateListDrawable是在view状态切换时可以实现两个状态直接的渐变
如果想了解更多,需要对drawable有所了解.
四、属性动画原理(Property Animation)
原理:使用了Choreographer机制
简单的说,Chreographer是组织上层进行处理绘制的控制类,它会在每次vsync信号来临时,执行与绘制相关的过程.
属性动画相关的方法在源码中所在的位置是frameworks/base/core/java/android/view/animation
属性动画的基类是Animator.
与Animation(补间动画)不同,Animator的确定过程发生在绘制之前(甚至是布局之前).
因为ValueAnimator引入了Choreographer,Choreographer是Vsync信号到来后进行view更新的控制类。
它通过mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mAnimate, null);
这个动作来实现下次绘制之前,可以执行mAnimate任务来设置view的一些属性来实现动画。
上述所说的view的一些属性包括X,translateX,TranslateZ,ScaleX......等属性

对这些属性的控制都会放到一个矩阵(Matrix),而这个矩阵放在RenderNode中
需要注意的是,虽然RenderNode主要为硬件渲染服务,但是它保存了一些属性是软件渲染也需要的,比如上面说的矩阵.
通过硬件加速绘制时,因为矩阵已经在RenderNode中了,所以在draw方法中不用做特殊处理.
而在软件渲染中(draw方法),
if (!childHasIdentityMatrix && !drawingWithRenderNode) {
canvas.translate(-transX, -transY);
canvas.concat(getMatrix());
canvas.translate(transX, transY);
}
其中,childHasIdentityMatrix 代表是不是单位矩阵
drawingWithRenderNode 代表是不是开启了硬件加速
说明:
观察ValueAnimator的源码
发现方法
private void scheduleAnimation() {
if (!mAnimationScheduled) {
mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mAnimate, null);
mAnimationScheduled = true;
}
}
以及mAnimate为
// Called by the Choreographer.
final Runnable mAnimate = new Runnable() {
@Override
public void run() {
mAnimationScheduled = false;
doAnimationFrame(mChoreographer.getFrameTime());
}

};
你如果对ValueAnimator添加了更新监听(addUpdateListener)
那么你可以在每次更新的回调(发生在上面的doAnimationFrame里[实际是animateValue])
比如进行view.setTranslateX(10),这种处理在随后的绘制中就会有所体现
参考文档:
http://www.cnblogs.com/whoislcj/p/5730520.html
https://en.wikipedia.org/wiki/Identity_matrix
http://zuiniuwang.blog.51cto.com/3709988/721798/
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2016/1214/6858.html

转载于:https://www.cnblogs.com/vete-l/p/7063285.html

Android动画原理相关推荐

  1. android 动画原理二

    简介: 这是由两部分组成的 Android 动画框架详解的第二部分实例篇.在阅读本篇之前,建议您首先阅读本系列的第一部分 Android 动画框架详解之原理篇.原理篇详细介绍了 Android 动画框 ...

  2. android 补间动画有停顿,Android动画原理分析(一)----补间动画

    1.基本特点 补间动画(Tween动画),是android最早的动画框架,从Android1.0开始就有. 功能:可以实现移动.旋转.缩放.渐变四种效果以及这四种效果的组合形式. 实现形式:xml和代 ...

  3. 打造简易NineoldAndroids动画库,深入理解Android动画原理

    简介 NineoldAndroids是Github上一个著名的动画库,简单来说,NineOldAndroids是一个向下兼容的动画库,主要是使低于API 11的系统也能够使用View的属性动画. 网上 ...

  4. Android动画原理分析

    最近在Android上做了一些动画效果,网上查了一些资料,有各种各样的使用方式,于是乘热打铁,想具体分析一下动画是如何实现的,Animation, Animator都有哪些区别等等. 首先说Anima ...

  5. Android 动画原理

    简介 Android 平台提供了三类动画,1.Tween动画,就是对场景里的对象不断的进行图像变化来产生动画效果(旋转.平移.放缩和渐变):2. Frame动画,即顺序的播放事先做好的图像,与gif图 ...

  6. android动画原理,最详细的解释小白也能听懂,值得收藏!

    面试如作战,我们看战争影视剧的时候,经常看到这些剧作往往主要聚焦于作战过程.战场战略,对战前准备给的篇幅往往很少.实际上,战前准备也是关键的一环,没有充足的粮草.车马.兵器的准备.别说赢得战争,投入战 ...

  7. Android 补间动画原理

    这段时间项目中用到了动画,所以趁热打铁,看看动画原理 补间动画 使用举例 TranslateAnimation translateAnim = new TranslateAnimation(0, 10 ...

  8. android 动画面试

    动画详解 参考:https://www.jianshu.com/p/2fcd4e734a01 三种动 1.视图动画(view Animation) 2.帧动画() 3.属性动画 插值器(Interpo ...

  9. android动画的实现原理,Android动画的实现原理 .

    1.动画运行模式 独行模式 中断模式 2.Animation类 每个动画都重载了父类的applyTransformation方法这个方法的主要作用是把一些属性组装成一个Transformation类, ...

最新文章

  1. 机器学习中目标函数、损失函数、代价函数之间的区别和联系
  2. graphpad做折线图坐标轴数字_多组数据制作折线图,四步让你的图表实用又美观,老板看了都说好...
  3. mac下MongoDB数据库安装
  4. OpenCASCADE:Modeling Data之3D几何
  5. charles抓包工具使用指南
  6. adobe acrobat看PDF文档显示字体发虚,有毛刺的解决办法
  7. 刚体转动惯量的测定实验数据软件_物理吸附实验数据分析 第11部分 在Origin软件中由物理吸附等温线确定材料的t图比表面积的方法...
  8. java编码native2ascii下载_使用native2ascii 中文字符与Unicode编码相互转换
  9. 手游图片素材提取_游戏资源提取工具(ExtractData日本游戏看内涵图)V2.5.38.966官方版下载 - 下载吧...
  10. 惠斯通电桥电路 轴扭矩 计算
  11. 博图注册表删除方法_安装西门子软件反复提示重启电脑的解决方法
  12. x内存满白苹果解决_苹果x出现白苹果的现象及解决办法
  13. python怎么定义向量类_python的用户定义向量类
  14. lh服务器注册,登不进去的人请看这里:LH服无法登录问题官方解释
  15. 计算机组成北大,计算机组成原理-PKUSEI.PDF
  16. 在c语言中int i k d,c语言int *pInt=(int *)d; 什么意思?
  17. 高德地图(AMap)JavaScript API的使用
  18. 计算机专项培训ppt,【图】- PPT专项培训 3天让你成为PPT高手爱联地铁口 - 深圳龙岗龙岗中心城电脑培训 - 深圳百姓网...
  19. 网页字体在Frontpage2000制作网页中的讲解
  20. 单片机课设基于51单片机的波形发生器(公开资源)(四种波形)(同时输出两种波形)

热门文章

  1. The Triangle
  2. druid连接池初始化慢_从零开始手写 mybatis (三)jdbc pool 从零实现数据库连接池
  3. html请求接口_通用网关接口-FastCGI介绍
  4. 可用子网数要不要减2_CCNA最实用的复习知识点(2)
  5. 计算机图形学画圆和直线代码,计算机图形学作业(中点法画直线和八分画圆法).doc...
  6. Mac更新VSCode写权限被拒绝 Cannot update while running on a read-only volume
  7. 完全平方数—leetcode279
  8. 内存的静态分配和动态分配的区别【转】
  9. Pixhawk-姿态解算-互补滤波
  10. HDU1569 方格取数(2)(二分图带权最大独立集 - 最小割应用)