Android animation
动画的意思就是一连串画面动起来了,根据这一连串画面的产生原理可分为两类:补间动画(Tween animation)和帧动画(frame animation)。补间动画只需要指定关键帧,剩下的所有画面由软件算法产生,不同的设备受性能影响运行效果也会不一样,适合用来实现一些简单规律的视图变换效果。帧动画就是逐帧显示播放UI制作好的资源画面,缺点是UI工作量大但能实现一些很逼真的复杂动画。
在android系统中用View Animation实现补间动画,Android 3.0加入Property Animation用来拓展和增强补间动画效果表现,Drawable Animation则是用来实现帧动画,利用android系统提供的接口和组件我们可以实现任何创意师所构思出的动画效果。
动画分类
在xml里面定义一连串图片和图片的持续时间,然后依次显示出来。原理和胶片电影是一样的。frameanimation .xml定义如下:
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false"> <item android:drawable="@drawable/icon1"android:duration="100"></item> <item android:drawable="@drawable/icon2"android:duration="80"></item> <item android:drawable="@drawable/icon3"android:duration="60"></item> <item android:drawable="@drawable/icon4"android:duration="50"></item> </animation-list>
代码中使用该动画:
imageview2.setBackgroundResource(R.anim.frameanimation); mAnimationDrawable = (AnimationDrawable) imageview2.getBackground(); mAnimationDrawable.start();
tips:1.这种动画的原理是利用人眼的视觉残留效应,理论上每秒24帧就能达到流畅体验,很适合于展现表演细腻的动画。例如:人物或动物急剧转身、头发及衣服的飘动、走路、说话以及精致的3D效果等。电影,以及一些早期制作精良的动画都是这么制作出来的。缺点也很明显,动画的原素材极大,播放这种动画系统资源开销也大。在手机中代表性的应用场景就是开关机动画。
2.TransitionDrawable用来实现两种图片之间互相渐变的效果。它不属于动画分类,但用法和效果都很类似。
最早出现的动画形式,可以对view进行旋转,位移,拉伸,透明度等动画,一般会在xml里定义,然后代码引用。Xml定义如下:
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@[package:]anim/interpolator_resource" android:shareInterpolator=["true" | "false"] > <alpha android:fromAlpha="float" android:toAlpha="float" /> <scale android:fromXScale="float" android:toXScale="float" android:fromYScale="float" android:toYScale="float" android:pivotX="float" android:pivotY="float" /> <translate android:fromXDelta="float" android:toXDelta="float" android:fromYDelta="float" android:toYDelta="float" /> <rotate android:fromDegrees="float" android:toDegrees="float" android:pivotX="float" android:pivotY="float" /> <set> ... </set> </set>
代码中引用该动画:
View mView = findViewById(R.id.view); Animation hyperspaceJump = AnimationUtils.loadAnimation(this, R.anim.hyperspace_jump); mView.startAnimation(hyperspaceJump);
tips:这应该是小伙伴们最早接触的动画方式了,没有之一。它结构优雅,使用方便,还能重用,在android3.0以前的应用绝大部分的动画都是使用该方式实现。但事物总有它的局限性,一个view限定词已经说明了他的适用范围。
Android3.0引入的一种新的动画方式,功能强大,使用简单,功能上可以完全取代view animation。它作用的对象是object,通过改变对象的属性最终产生动画或其他效果,该对象可以是看得见的view,也可以是看不见的view或者其他非view组件。
我们看下它的xml定义(property_animator.xml):
<set android:ordering="sequentially"> <set> <objectAnimator android:propertyName="x" android:duration="500" android:valueTo="400" android:valueType="intType"/> <objectAnimator android:propertyName="y" android:duration="500" android:valueTo="300" android:valueType="intType"/> </set> <objectAnimator android:propertyName="alpha" android:duration="500" android:valueTo="1f"/> </set>
代码中引用该动画:
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,R.anim.property_animator); set.setTarget(myObject); set.start();
通过阅读源代码和实际使用来看property animation 在代码中直接定义更常见:
/* * ---------------------for propertyanimation------------------ */ /* * alpha animation */ // mAnimator1= ObjectAnimator.ofFloat(bt2, "alpha", 0f,1f); /* * motion animation */ // mAnimator1= ObjectAnimator.ofFloat(bt2, "X", 0f,400f,80f); /* * scale animation */ // mAnimator1= ObjectAnimator.ofFloat(bt2, "scaleX", 0f,10f,1); /* * rotation animation */ // mAnimator1= ObjectAnimator.ofFloat(bt2, "rotationX", 0f,360f,60f); // mAnimator1.setDuration(500); // mAnimator3= ObjectAnimator.ofFloat(bt2, "rotationY", 0f,360f,60f); // mAnimator3.setDuration(500); // mAnimator1= ObjectAnimator.ofFloat(bt2, "rotation", 0f,360f,60f); // mAnimator1.setDuration(500); /* * color animation */ mAnimator4 = ObjectAnimator.ofInt(imageview1, "backgroundColor",0xFFFF7F00,0xFFFFFAFA); mAnimator4.setDuration(500); mAnimator1 = ObjectAnimator.ofFloat(textview1, "rotation",0f,3600f); mAnimator1.setDuration(500); mAnimator3 = ObjectAnimator.ofFloat(textview1, "Y", 0f,360f,60f); mAnimator3.setDuration(500); mAnimator2 = ObjectAnimator.ofFloat(bt2, "alpha",0f,1f,0.2f); mAnimator2.setDuration(500); mAnimatorSet1 = new AnimatorSet(); mAnimatorSet1.play(mAnimator1).with(mAnimator2); mAnimatorSet1.play(mAnimator1).with(mAnimator3); // start property animation. mAnimatorSet1.start();
1.view animation只能作用在view对象上面,而property animation没有这种限制,只要是对象都可以。
2.property animation可以改变背景(color),而view animation只能改变形状和位置。
3.view animation只是改变了view的位置,而不会改变view的响应区域。
4.对于有多个动画同时运行的情况property animation的效率会高于view animation。原因是两种动画的刷新机制不同,属性动画通过减少刷新的区域和次数来提高效率。
5.配合android 3.0开放的Hardware Acceleration,属性动画可以大有所为。
一般叫它插值器,通过它我们可以让动画成非线性变得更生动,如加速,减速,回弹等效果,在PropertyAnimation中是TimeInterplator,在ViewAnimation中是Interplator,这两个是一样的,在3.0之前只有Interplator,3.0之后实现代码转移至了TimeInterplator。Interplator继承自TimeInterplator,内部没有任何其他代码。系统有以下几种默认效果:
Animator.AnimatorListener
onAnimationStart()
onAnimationEnd()
onAnimationRepeat()
//当动画被取消时调用,同时会调用onAnimationEnd().
onAnimationCancel()
ValueAnimator.AnimatorUpdateListener
onAnimationUpdate()//通过监听这个事件在属性的值更新时执行相应的操作,对于ValueAnimator一般要监听此事件执行相应的动作,不然Animation没意义,在ObjectAnimator(继承自ValueAnimator)中会自动更新属性,如无必要不必监听。在函数中会传递一个ValueAnimator参数,通过此参数的getAnimatedValue()取得当前动画属性值。
可以继承AnimatorListenerAdapter而不是实现AnimatorListener接口来简化操作,这个类对AnimatorListener中的函数都定义了一个空函数体,这样我们就只用定义想监听的事件而不用实现每个函数却只定义一空函数体。
ObjectAnimatoroa=ObjectAnimator.ofFloat(tv, "alpha", 0f, 1f); oa.setDuration(3000); oa.addListener(new AnimatorListenerAdapter(){ public void on AnimationEnd(Animator animation){ Log.i("Animation","end"); } }); oa.start();
1.有alpha变化时尽量开启硬件加速
当使用 setAlpha(), AlphaAnimation, or ObjectAnimator对
view
进行变化时,系统需要两倍的填充速率来完成离屏缓冲
buffer
。开启硬件加速能很大程度优化该过程。
2.
复杂动画建议开启硬件加速。
当系统的drawing operations太多,这时动画并不能保证有每秒60帧。开启硬件加速后,会生成一个硬件纹理用来作用于view的动画,而且只在view的属性发生改变时或强制invalidate()才会重绘。减少了view的无效刷新,所以会更流畅。
Tips:当你的动画没有达到预期效果,而且还是property animation时,可以开启硬件加速试试(意想不到的效果哦)。
3.在使用一些android.graphics.*api时,如果没有效果,或某些机子效果不到位,这时开启硬件加速或许就好了。在做一个类似于ios锁屏滑动解锁效果时就遇到该问题和编译系统的策略有关(是否默认开启硬件加速):
//开启硬件加速后,下面的代码才能同时在4.2和4.0上有效果。
setLayerType(LAYER_TYPE_HARDWARE, null); mPaint.setXfermode(newPorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
tips:也不是任何地方开启硬件加速就是使体验更好,如果gpu性能太差,如一些mtk,联发科低端机型,还是使用view缓存的效率更高:
button.setChildrenDrawnWithCacheEnabled(true); button.setChildrenDrawingCacheEnabled(true);