android 动画.docx
- 文档编号:11242995
- 上传时间:2023-02-26
- 格式:DOCX
- 页数:35
- 大小:318.43KB
android 动画.docx
《android 动画.docx》由会员分享,可在线阅读,更多相关《android 动画.docx(35页珍藏版)》请在冰豆网上搜索。
android动画
Android动画框架详解,第1部分
简介:
Android平台提供了一套完整的动画框架,使得开发者可以用它来开发各种动画效果。
Android动画框架详解由原理篇和实例篇两部分组成。
本文是第一部分原理篇,主要分析Tween动画的实现原理,最后简单介绍在Android中如何通过播放Gif文件来实现动画。
第二部分实例篇将在原理篇的基础上,向您展示一个动画实例的实现。
Android平台提供了一套完整的动画框架,使得开发者可以用它来开发各种动画效果,本文将向读者阐述Android的动画框架是如何实现的。
任何一个框架都有其优势和局限性,只有明白了其实现原理,开发者才能知道哪些功能可以利用框架来实现,哪些功能须用其他途径实现。
Android平台提供了两类动画,一类是Tween动画,即通过对场景里的对象不断做图像变换(平移、缩放、旋转)产生动画效果;第二类是Frame动画,即顺序播放事先做好的图像,跟电影类似。
本文是由两部分组成的有关Android动画框架详解的第一部分原理篇,主要分析Tween动画的实现原理,最后简单介绍在Android中如何通过播放Gif文件来实现动画。
我们先看一下动画示例来一点感性认识。
Android动画使用示例
使用动画示例程序的效果是点击按钮,TextView旋转一周。
读者也可以参看Apidemos中包com.example.android.apis.animationview下面的Transition3d和com.example.android.apis.view下面的Animation1/Animation2/Animation3示例代码。
清单1.代码直接使用动画
packagecom.ray.animation;
importandroid.app.Activity;
importandroid.os.Bundle;
importandroid.view.View;
importandroid.view.View.OnClickListener;
importandroid.view.animation.AccelerateDecelerateInterpolator;
importandroid.view.animation.Animation;
importandroid.view.animation.RotateAnimation;
importandroid.widget.Button;
publicclassTestAnimationextendsActivityimplementsOnClickListener{
publicvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Buttonbtn=(Button)findViewById(R.id.Button);
btn.setOnClickListener(this);
}
publicvoidonClick(Viewv){
Animationanim=null;
anim=new?
RotateAnimation(0.0f,+360.0f);
anim.setInterpolator(newAccelerateDecelerateInterpolator());
anim.setDuration(3000);
findViewById(R.id.TextView01).startAnimation(anim);
}
}
使用XML文件方式,在打开Eclipse中新建的Android工程的res目录中新建anim文件夹,然后在anim目录中新建一个myanim.xml(注意文件名小写),内容如下:
图1.使用xml文件方式
其中的java代码如下:
packagecom.ray.animation;
importandroid.app.Activity;
importandroid.os.Bundle;
importandroid.view.View;
importandroid.view.View.OnClickListener;
importandroid.view.animation.Animation;
importandroid.view.animation.AnimationUtils;
importandroid.widget.Button;
importandroid.widget.TextView;
publicclassTestAnimationextendsActivityimplementsOnClickListener{
publicvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Buttonbtn=(Button)findViewById(R.id.Button01);
btn.setOnClickListener(this);
}
@Override
publicvoidonClick(Viewv){
Animationanim=AnimationUtils.loadAnimation(this,R.anim.my_rotate_action);
findViewById(R.id.TextView01).startAnimation(anim);
}
}
回页首
Android动画框架原理
现有的Android动画框架是建立在View的级别上的,在View类中有一个接口startAnimation来使动画开始,startAnimation函数会将一个Animation类别的参数传给View,这个Animation是用来指定我们使用的是哪种动画,现有的动画有平移,缩放,旋转以及alpha变换等。
如果需要更复杂的效果,我们还可以将这些动画组合起来,这些在下面会讨论到。
要了解Android动画是如何画出来的,我们首先要了解Android的View是如何组织在一起,以及他们是如何画自己的内容的。
每一个窗口就是一棵View树,下面以我们写的android_tabwidget_tutorial.doc中的tab控件的窗口为例,通过android工具hierarchyviewer得到的窗口ViewTree如下图1所示:
图2.界面View结构图
图3.界面View结构和显示对应图
其实这个图不是完整的,没有把RootView和DecorView画出来,RootView只有一个孩子就是DecorView,这里整个ViewTree都是DecorView的子View,它们是从android1.5/frameworks/base/core/res/res/layout/screen_title.xml这个layout文件infalte出来的,感兴趣的读者可以参看frameworks\policies\base\phone\com\android\internal\policy\Imp\PhoneWindow.java中generateLayout函数部分的代码。
我们可以修改布局文件和代码来做一些比较cool的事情,如象Windows的缩小/关闭按钮等。
标题窗口以下部分的FrameLayou就是为了让程序员通过setContentView来设置用户需要的窗口内容。
因为整个View的布局就是一棵树,所以绘制的时候也是按照树形结构遍历来让每个View进行绘制。
ViewRoot.java中的draw函数准备好Canvas后会调用mView.draw(canvas),其中mView就是调用ViewRoot.setView时设置的DecorView。
然后看一下View.java中的draw函数:
递归的绘制整个窗口需要按顺序执行以下几个步骤:
1绘制背景;
2如果需要,保存画布(canvas)的层为淡入或淡出做准备;
3绘制View本身的内容,通过调用View.onDraw(canvas)函数实现,通过这个我们应该能看出来onDraw函数重载的重要性,onDraw函数中绘制线条/圆/文字等功能会调用Canvas中对应的功能。
下面我们会drawLine函数为例进行说明;
4绘制自己的孩子(通常也是一个view系统),通过dispatchDraw(canvas)实现,参看ViewGroup.Java中的代码可知,dispatchDraw->drawChild->child.draw(canvas)这样的调用过程被用来保证每个子View的draw函数都被调用,通过这种递归调用从而让整个View树中的所有View的内容都得到绘制。
在调用每个子View的draw函数之前,需要绘制的View的绘制位置是在Canvas通过translate函数调用来进行切换的,窗口中的所有View是共用一个Canvas对象
5如果需要,绘制淡入淡出相关的内容并恢复保存的画布所在的层(layer)
6绘制修饰的内容(例如滚动条),这个可知要实现滚动条效果并不需要ScrollView,可以在View中完成的,不过有一些小技巧,具体实现可以参看我们的TextViewExample示例代码
当一个ChildView要重画时,它会调用其成员函数invalidate()函数将通知其ParentView这个ChildView要重画,这个过程一直向上遍历到ViewRoot,当ViewRoot收到这个通知后就会调用上面提到的ViewRoot中的draw函数从而完成绘制。
View:
:
onDraw()有一个画布参数Canvas,画布顾名思义就是画东西的地方,Android会为每一个View设置好画布,View就可以调用Canvas的方法,比如:
drawText,drawBitmap,drawPath等等去画内容。
每一个ChildView的画布是由其ParentView设置的,ParentView根据ChildView在其内部的布局来调整Canvas,其中画布的属性之一就是定义和ChildView相关的坐标系,默认是横轴为X轴,从左至右,值逐渐增大,竖轴为Y轴,从上至下,值逐渐增大,见下图:
图4.窗口坐标系
Android动画就是通过ParentView来不断调整ChildView的画布坐标系来实现的,下面以平移动画来做示例,见下图4,假设在动画开始时ChildView在ParentView中的初始位置在(100,200)处,这时ParentView会根据这个坐标来设置ChildView的画布,在ParentView的dispatchDraw中它发现ChildView有一个平移动画,而且当前的平移位置是(100,200),于是它通过调用画布的函数traslate(100,200)来告诉ChildView在这个位置开始画,这就是动画的第一帧。
如果ParentView发现ChildView有动画,就会不断的调用invalidate()这个函数,这样就会导致自己会不断的重画,就会不断的调用dispatchDraw这个函数,这样就产生了动画的后续帧,当再次进入dispatchDraw时,ParentView根据平移动画产生出第二帧的平移位置(500,200),然后继续执行上述操作,然后产生第三帧,第四帧,直到动画播完。
具体算法描述如清单2:
清单2.算法
dispatchDraw()
{
....
Animationa=ChildView.getAnimation()
Transformationtm=a.getTransformation();
UsetmtosetChildView'sCanvas;
Invalidate();
....
}
图5.平移动画示意图
以上是以平移动画为例子来说明动画的产生过程,这其中又涉及到两个重要的类型,Animation和Transformation,这两个类是实现动画的主要的类,Animation中主要定义了动画的一些属性比如开始时间、持续时间、是否重复播放等,这个类主要有两个重要的函数:
getTransformation和applyTransformation,在getTransformation中Animation会根据动画的属性来产生一系列的差值点,然后将这些差值点传给applyTransformation,这个函数将根据这些点来生成不同的Transformation,Transformation中包含一个矩阵和alpha值,矩阵是用来做平移、旋转和缩放动画的,而alpha值是用来做alpha动画的(简单理解的话,alpha动画相当于不断变换透明度或颜色来实现动画),以上面的平移矩阵为例子,当调用dispatchDraw时会调用getTransformation来得到当前的Transformation,这个Transformation中的矩阵如下:
图6.矩阵变换图
所以具体的动画只需要重载applyTransformation这个函数即可,类层次图如下:
图7.动画类继承关系图
用户可以定义自己的动画类,只需要继承Animation类,然后重载applyTransformation这个函数。
对动画来说其行为主要靠差值点来决定的,比如,我们想开始动画是逐渐加快的或者逐渐变慢的,或者先快后慢的,或者是匀速的,这些功能的实现主要是靠差值函数来实现的,Android提供了一个Interpolator的基类,你要实现什么样的速度可以重载其函数getInterpolation,在Animation的getTransformation中生成差值点时,会用到这个函数。
从上面的动画机制的分析可知某一个View的动画的绘制并不是由他自己完成的而是由它的父view完成,所有我们要注意上面TextView旋转一周的动画示例程序中动画的效果并不是由TextView来绘制的,而是由它的父View来做的。
findViewById(R.id.TextView01).startAnimation(anim)这个代码其实是给这个TextView设置了一个animation,而不是进行实际的动画绘制,代码如下:
publicvoidstartAnimation(Animationanimation){animation.setStartTime(Animation.START_ON_FIRST_FRAME);setAnimation(animation);invalidate();}
其他的动画机制的代码感兴趣的读者请自己阅读,希望通过原理的讲解以后看起来会轻松点,呵呵。
以上就是Android的动画框架的原理,了解了原理对我们的开发来说就可以清晰的把握动画的每一帧是怎样生成的,这样便于开发和调试。
它把动画的播放/绘制交给父View去处理而不是让子View本身去绘制,这种从更高的层次上去控制的方式便于把动画机制做成一个易用的框架,如果用户要在某个view中使用动画,只需要在xml描述文件或代码中指定就可以了,从而把动画的实现和View本身内容的绘制(象TextView里面的文字显示)分离开了,起到了减少耦合和提高易用性的效果。
回页首
动画实现示例
在这个例子中,将要实现一个绕Y轴旋转的动画,这样可以看到3D透视投影的效果,代码如下(清单4):
清单3.实现一个绕Y轴旋转的动画
packagecom.example.android.apis.animation;
importandroid.view.animation.Animation;
importandroid.view.animation.Transformation;
importandroid.graphics.Camera;
importandroid.graphics.Matrix;
/**
*AnanimationthatrotatestheviewontheYaxisbetweentwospecifiedangles.
*ThisanimationalsoaddsatranslationontheZaxis(depth)toimprovetheeffect.
*/
publicclassRotate3dAnimationextendsAnimation{
privatefinalfloatmFromDegrees;
privatefinalfloatmToDegrees;
privatefinalfloatmCenterX;
privatefinalfloatmCenterY;
privatefinalfloatmDepthZ;
privatefinalbooleanmReverse;
privateCameramCamera;
/**
*Createsanew3DrotationontheYaxis.Therotationisdefinedbyits
*startangleanditsendangle.Bothanglesareindegrees.Therotation
*isperformedaroundacenterpointonthe2Dspace,definiedbyapair
*ofXandYcoordinates,calledcenterXandcenterY.Whentheanimation
*starts,atranslationontheZaxis(depth)isperformed.Thelength
*ofthetranslationcanbespecified,aswellaswhetherthetranslation
*shouldbereversedintime.
*
*@paramfromDegreesthestartangleofthe3Drotation
*@paramtoDegreestheendangleofthe3Drotation
*@paramcenterXtheXcenterofthe3Drotation
*@paramcenterYtheYcenterofthe3Drotation
*@paramreversetrueifthetranslationshouldbereversed,falseotherwise
*/
publicRotate3dAnimation(floatfromDegrees,floattoDegrees,
floatcenterX,floatcenterY,floatdepthZ,booleanreverse){
mFromDegrees=fromDegrees;
mToDegrees=toDegrees;
mCenterX=centerX;
mCenterY=centerY;
mDepthZ=depthZ;
mReverse=reverse;
}
@Override
publicvoidinitialize(intwidth,intheight,intparentWidth,intparentHeight){
super.initialize(width,height,parentWidth,parentHeight);
mCamera=newCamera();
}
@Override
protectedvoidapplyTransformation(floatinterpolatedTime,Transformationt){
finalfloatfromDegrees=mFromDegrees;
floatdegrees=fromDegrees+((mToDegrees-fromDegrees)*interpolatedTime);
finalfloatcenterX=mCenterX;
finalfloatcenterY=mCenterY;
finalCameracamera=mCamera;
finalMatrixmatrix=t.getMatrix();
camera.save();
if(mReverse){
camera.translate(0.0f,0.0f,mDepthZ*interpolatedTime);
}else{
camera.translate(0.0f,0.0f,mDepthZ*(1.0f-interpolatedTime));
}
camera.rotateY(degrees);
camera.getMatrix(matrix);
camera.restore();
matrix.preTranslate(-centerX,-centerY);
matrix.postTranslate(centerX,centerY);
}
}
在这个例子中我们重载了applyTransformation函数,interpolatedTime就是getTransformation函数传下来的差值点,在这里做了一个线性插值算法来生成中间角度:
floatdegrees=fromDegrees+((mToDegrees-from
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- android 动画