动画模式在android系统中被分为三类,分别为:
- tween(view) animation:补间动画frame(drawable) animation:逐帧动画property animation:属性动画
本章节分别对齐进行解读。
1 Tween Animation 1.1 Tween Animation基础Animation是以XML格式定义的,XML文件存放在路径res/anim下。这里按照XML文档的结构{父节点|子节点|属性}来介绍Tween Animation。先介绍Tween Animation共同的节点属性,如下所示:
Tween Animation由4种基本动画组成:Alpha(渐变透明度)、Scale(缩放)、Translate(位置移动)、Rotate(旋转),同时Animation类还有AlphaAnimation、ScaleAnimation、 TranslateAnimation、RotateAnimation 4个子类与之分别对应,每个子类都在父类的基础上增加了各自独有的属性。分别解读如下:
@1 Alpha属性说明:
@2 Scale属性说明:
@3 Translate属性说明:
@4 Rotate属性说明:
1.2 Tween Animation的用法Tween Animation的用法有2种:从XML文件中读取 和 代码中设置/读取。
@1 代码中直接从XML资源中读取Animation并使用
用XML定义的动画放在/res/anim/文件夹内,XML文件的根元素可以为,
ImageView XXXImage = (ImageView)findViewById(R.id.spaceshipImage); Animation yyyAnimation=AnimationUtils.loadAnimation(this,R.anim.yyy); XXXImage.startAnimation(yyyAnimation);
@2 通过代码设置Tween Animation属性
代码中使用Animation子类来初始化Animation对象。Animation基类包含大量的set/getXXX()函数来设置/读取Animation的属性。相关方法可参照文档:Android Animation XML属性。
Tween Animation关于动画相关的方法可参照文档:Android Animation method解读。
1.3 动画的运行控制与模式@1 Interpolator
动画的进度使用 Interpolator来控制,interpolator定义一个动画的变化率,用于在运行时控制动画。这使得基本的动画效果(alpha, scale, translate, rotate)得以加速,减速,重复等。Interpolator 是基类,封装了所有 Interpolator 的共同方法,它只有一个方法,即 getInterpolation (float input),该方法提供了几个Interpolator 子类,实现了不同的速度曲线,如下:
说明:对于 LinearInterpolator ,变化率是个常数,即f(x) = x。Interpolator其他的几个子类,也都是按照特定的算法,实现了对变化率。还可以定义自己的Interpolator子类,实现抛物线、自由落体等物理效果。
@2 动画运行模式
独占模式:程序主线程进入一个循环,根据动画指令不断刷新屏幕,直到动画结束。中断模式:单独线程对时间计数,隔一段时间给主线程发通知,主线程接到通知后更新屏幕。
@3 动画实现原理
Transformation记录了仿射矩阵Matrix,动画每触发一次,会对原来的矩阵做一次运算, View的Bitmap与这个矩阵相乘就可实现相应的 *** 作(旋转、平移、缩放等)。图形变换通过仿射矩阵实现。图形变换是图形学中的基本知识,简单来讲,每种变换都是一次矩阵运算。在 Android中,Canvas 类中包含当前矩阵,当调用Canvas.drawBitmap(bmp, x, y, Paint)绘制时,Android会先把bmp做一次矩阵运算,然后将运算的结果显示在Canvas上。之后只需不断修改Canvas的矩阵并刷新屏幕,View里的对象就会不停的做图形变换,因此就形成了动画。 2 frame Animation
Android用AnimationDrawable类来定义和使用frame Animation。它可以在XML Resource定义(还是存放到res/anim文件夹下),也可以使用AnimationDrawable中的API定义。与Tween Animation不同,frame Animation是顺序播放事先做好的图像,通过一系列Drawable依次显示来模拟动画的效果。在XML中的定义方式如下:
- ...
说明:必须以为根元素,以
@2 Drawable Animation使用示例:
定义一帧一帧的动画item,配置如下所示:
其包含3帧动画,3帧动画中分别应用了drawable中的3张图片:XXX1、XXX2、XXX3,每帧动画持续200毫秒。然后我们将以上XML保存在res/anim/文件夹下,命名为XXX.xml。
编写代码,显示动画的代码如下:
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); imageView = (ImageView) findViewById(R.id.imageView); imageView.setBackgroundResource(R.drawable.drawable_anim); anim = (AnimationDrawable) imageView.getBackground(); } public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { anim.stop(); anim.start(); return true; } return super.onTouchEvent(event); }
注意:
调用Imageview的setBackgroundResource方法,如果直接在XML布局文件中设置其src属性,当触发动画时会ForceClose问题。在start()前要先stop(),不然第一次动画运行后会停在最后一帧,这样动画就只会触发一次。不要在onCreate中调用start,因为AnimationDrawable还没有完全跟Window相关联,如果想要界面显示时就开始动画的话,可以在onWindowFoucsChanged()中调用start()。
@3 阅读Android 文档中对AnimationDrawable的介绍,关键内容整理如下:
更多关于AnimationDrawable的介绍,查看文档:Android AnimationDrawable详细解读
注意:frame Animation 的XML 文件中不定义 interpolator 属性,因为定义它没有任何意义。
3 AnimatorAnimator代表一个属性动画,但是它只是一个抽象类。我们通常会使用它的子类:AnimatiorSet、ValueAnimator、ObjectAnimator、TimeAnimator。XML文件应放在res/animator/中。
3.1 属性动画的工作方式@1 属性动画,它更改对象的实际属性。
在Tween Animation中,其改变的是View的绘制效果,View的属性保持不变,比如无论你在对话中如何缩放Button的大小,Button有效点击区域还是没有应用动画时的区域,其位置与大小都不变。在属性动画中,改变的是对象的实际属性,如Button的缩放,Button的位置与大小属性值都改变了。且属性动画不止可以应用于View,还可以应用于任何对象。属性动画只是表示一个值在一段时间内的改变,当值改变时要做什么事情由我们来决定。
@2 在Property Animation中,可以对动画应用以下属性:
3.2 常见属性动画解读&代码使用实例 3.2.1 ValueAnimator动画(代码实现机制)整个属性动画机制当中最核心的一个类,属性动画的运行机制是通过不断地对值进行 *** 作来实现的,而初始值和结束值之间的动画过渡就是由ValueAnimator这个类来负责计算的。它的内部使用一种时间循环的机制来计算值与值之间的动画过渡,我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果。除此之外,ValueAnimator还负责管理动画的播放次数、播放模式、以及对动画设置监听器等,是一个非常重要的类。但是ValueAnimator的用法却一点都不复杂,实例(将一个值从0平滑过渡到1,时长300毫秒,就可以这样写)如下:
ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f); anim.setDuration(300); anim.start();3.2.2 ObjectAnimator动画(代码实现机制)
相比于ValueAnimator,ObjectAnimator更常用,ValueAnimator不过是对值进行了平滑的动画过渡。而ObjectAnimator(继承自ValueAnimator)可以直接对任意对象的任意属性进行动画 *** 作。
@1 alpha案例
一个TextView在5秒中内从常规变换成全透明,再从全透明变换成常规,代码如下:
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f); animator.setDuration(5000); animator.start();
@2 rotation案例
将TextView进行一次360度的旋转,将@1中第二个参数改成"rotation",然后将动画的初始值和结束值分别设置成0和360,代码如下:
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "rotation", 0f, 360f); animator.setDuration(5000); animator.start();
@3 translation案例
将TextView先向左移出屏幕,然后再移动回来,代码如下:
float curTranslationX = textview.getTranslationX(); ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "translationX",curTranslationX, -500f, curTranslationX); animator.setDuration(5000); animator.start();
先是调用了TextView的getTranslationX()方法来获取到当前TextView的translationX的位置,然后ofFloat()方法的第二个参数传入"translationX",后面三个参数用于告诉TextView如何移动。
@4 Scale实例
将TextView在垂直方向上放大3倍再还原,将ofFloat()方法的第二个参数改成了"scaleY",表示在垂直方向上进行缩放,代码如下:
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "scaleY", 1f, 3f, 1f); animator.setDuration(5000); animator.start();
@5 特殊说明
关于 ofFloat()方法的第二个参数传递参数:不局限于alpha、rotation、translationX和scaleY这些值,我们可以传入任意值到ofFloat()方法的第2个参数。因为ObjectAnimator在设计的时候就没有针对于View来进行设计,而是针对于任意对象的,它所负责的工作就是不断地向某个对象中的某个属性进行赋值,然后对象根据属性值的改变再来决定如何展现出来。
3.2.3 组合动画@1 基本概念
独立动画实现的视觉效果有限,因此将多个动画组合到一起播放就显得尤为重要。实现组合动画主要借助AnimatorSet这个类,这个类提供了一个play()方法,传入Animator对象(ValueAnimator或ObjectAnimator)将会返回一个AnimatorSet.Builder实例,AnimatorSet.Builder中包括以下四个方法:
after(Animator anim) //将现有动画插入到传入的动画之后执行。 after(long delay) //将现有动画延迟指定毫秒后执行。 before(Animator anim) //将现有动画插入到传入的动画之前执行。 with(Animator anim) //将现有动画和传入的动画同时执行。
有这四个方法,我们就可以完成组合动画的逻辑。
@2 使用实例
这里让TextView先从屏幕外移动进屏幕,然后开始旋转360度,旋转的同时进行淡入淡出 *** 作,关键代码如下所示:
ObjectAnimator moveIn = ObjectAnimator.ofFloat(textview, "translationX", -500f, 0f); ObjectAnimator rotate = ObjectAnimator.ofFloat(textview, "rotation", 0f, 360f); ObjectAnimator fadeInOut = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f); AnimatorSet animSet = new AnimatorSet(); animSet.play(rotate).with(fadeInOut).after(moveIn); animSet.setDuration(5000); animSet.start();
先创建三个动画对象,然后new出一个AnimatorSet对象后将这三个动画对象进行播放排序,让旋转和淡入淡出动画同时进行,并把它们插入到了平移动画的后面,最后设置动画时长及启动动画。
3.3 属性动画XML使用实例 3.3.1 ValueAnimator动画使用实例ValueAnimator代码和xml设置中,因为不是 *** 作对象,所以没有setPropertyName,只是根据value进行某种动作需要加监听器,监听值的变化做相应的处理。xm配置如下:
加载XML动画,关键代码实现如下:
ValueAnimator valueAnimator = (ValueAnimator) AnimatorInflater.loadAnimator(this, R.animator.animator); valueAnimator.setTarget(tv_num); valueAnimator.setevaluator(new Typeevaluator3.3.2 ObjectAnimator动画XML的使用实例() { @Override public Integer evaluate(float fraction, Integer startValue, Integer endValue) { System.out.println("时间比率,fraction:" + fraction); System.out.println("结果值:" + (int)((startValue + fraction * (endValue - startValue)) / 10 * 10)); return (int)((startValue + fraction * (endValue - startValue)) / 10 * 10); } }); valueAnimator.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { //在onAnimationUpdate中 该值返回第一个动画的 当前帧的evaluate 值 System.out.println("animation.getAnimatedValue()==" + animation.getAnimatedValue()); tv_num.setText(animation.getAnimatedValue() + ""); } }); valueAnimator.start();
动画XML定义如下:
加载XML动画,关键代码如下所示:
imageview_scale.setBackground(getResources().getDrawable(R.drawable.a11)); ObjectAnimator scaleAnimator = (ObjectAnimator) AnimatorInflater.loadAnimator(this, R.animator.scale_object_animator); scaleAnimator.setTarget(imageview_scale);//设置动画作用的目标对象 scaleAnimator.setDuration(1000); scaleAnimator.setRepeatCount(50); scaleAnimator.start();3.3.3 AnimatorSet 动画集
由ObjectAnimator 和 ValueAnimator 组成,对应的xml中的写法类似为
... ...
xml定义动画集一般在文件夹res/animator下,这里是res/animator/set_rotate_scale.xml
@1 XML配置文件定义如下:
加载XML动画集,代码实现如下:
imageview_rotate.setBackground(getResources().getDrawable(R.drawable.a11)); AnimatorSet animatorSet = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.set_rotate_scale); animatorSet.setTarget(imageview_rotate); animatorSet.setDuration(1000); animatorSet.setInterpolator(new BounceInterpolator());//设置end时的d跳插入器 animatorSet.start();
更多关于动画的内容可查看文档:Android 动画解读
4 Animator监听器若我们希望监听到动画事件,动画何时开始,何时结束,然后在开始或者结束的时候去执行一些逻辑处理。这个功能是完全可以实现的,Animator类当中提供了一个addListener()方法,这个方法接收一个AnimatorListener,我们只需要去实现这个AnimatorListener就可以监听动画的各种事件了。
只要是继承自Animator的,addListener()这个方法算是个通用的方法,添加一个监听器的代码如下所示:
anim.addListener(new AnimatorListener() { @Override public void onAnimationStart(Animator animation) {} @Override public void onAnimationRepeat(Animator animation) {} @Override public void onAnimationEnd(Animator animation) {} @Override public void onAnimationCancel(Animator animation) {} });
但是也许很多时候我只想要监听动画响应的单一事件,那么可以使用AnimatorListenerAdapter,使用这个类就可以解决掉实现接口繁琐的问题了,如下所示:
anim.addListener(new AnimatorListenerAdapter() {});
这里我们向addListener()方法中传入这个适配器对象,由于AnimatorListenerAdapter中已经将每个接口都实现好了,所以这里不用实现任何一个方法也不会报错。那么如果想监听动画结束这个事件,就只需要单独重写这一个方法就可以了,如下所示:
anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { } });
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)