Android中动画分为3种:
ween Animation:通过对场景里的对象不断做图像变换(平移、缩放、旋转)产生动画效果,即是一种渐变动画;
也称View动画:也叫渐变动画,针对View的动画,主要支持平移、旋转、缩放、透明度
Frame Animation:顺序播放事先做好的图像,是一种画面转换动画。
Drawable动画:也叫帧动画,主要是设置View的背景,可以以动画的形式为View设置多张背景
Property Animation:属性动画,通过动态地改变对象的属性从而达到动画效果,属性动画为API 11新特性。
对象属性动画(Android3.0新加 入):可以对对象的属性进行动画而不仅仅是View,动画默认时间间隔300ms,默认帧率10ms/帧。其可以达到的效果是:在一个时间间隔内完成对象 从一个属性值到另一个属性值的改变,因此,属性动画几乎是无所不能的,只要对象有这个属性,它都能实现动画效果。
一 Tween Animation(View动画)
Tween Animation有四种形式:
l alpha 渐变透明度动画效果
l scale 渐变尺寸伸缩动画效果
l translate 画面位置移动动画效果
l rotate 画面旋转动画效果
Tween Animation有 2种使用方法:
a、在XML资源中定义Animation,使用AnimationUtils中的loadAnimation()函数加载动画;
b、使用Animation子类的构造函数来初始化Animation对象。
在xml实现:动画的XML文件在工程中res/anim目录。
<!--画面转移旋转动画效果:以组件的中点为中心顺时针从0度旋转到720度-->
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@mipmap/default_ptr_rotate_gray"
android:duration="700"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="720" />
或者
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter = "false"
android:zAdjustment="bottom" >
<rotate
android:fromDegrees="0"
android:toDegrees="360"
android:pivotX="50%"
android:pivotY="50%"
android:duration="4000"
/>
</set>
Alpha:
<alpha android:interpolator= “@android:anim/accelerate_decelerate_interpolator”
android:fromAlpha="1.0"
android:toAlpha="0.0"
android:duration="3000"
></alpha>
<!--
interpolator:指定一个动画的插入器,用来控制动画的速度变化
fromAlpha:动画起始时透明度
0.0表示完全透明
1.0表示完全不透明
以上值取0.0-1.0之间的float数据类型的数字
toAlpha:动画结束时透明度
duration:持续时间 -->
Scale:
<scale
android:interpolator= “@android:anim/accelerate_decelerate_interpolator”
android:fromXScale=”0.0″
android:toXScale=”1.4″
android:fromYScale=”0.0″
android:toYScale=”1.4″
android:pivotX=”50%”
android:pivotY=”50%”
android:fillAfter=”false”
android:startOffset=“700”
android:duration=”700″
android:repeatCount=”10″ />
<!--
fromXScale[float]:为动画起始时,X坐标上的伸缩尺寸,0.0表示收缩到没有
fromYScale[float]:为动画起始时,Y坐标上的伸缩尺寸,0.0表示收缩到没有
1.0表示正常无伸缩
值小于1.0表示收缩
值大于1.0表示放大
toXScale[float]:为动画结束时,X坐标上的伸缩尺寸
toYScale[float]:为动画结束时,X坐标上的伸缩尺寸
pivotX[float]:为动画相对于物件的X坐标的开始位置
pivotY[float]:为动画相对于物件的X、Y坐标的开始位置
50,50%,50%p。这三种写法就分别代表了ABSOLUTE,RELATIVE_TO_SELF和 RELATIVE_TO_PARENT。
属性值说明:从0%-100%中取值,50%为物件的X或Y方向坐标上的中点位置
fillAfter[boolean]:当设置为true ,该动画转化在动画结束后被应用
startOffset[long]:动画之间的时间间隔,从上次动画停多少时间开始执行下个动画
repeatCount[int]:动画的重复次数 -->
Translate:
<translate
android:interpolator=”@android:anim/accelerate_decelerate_interpolator”
android:fromXDelta=”30″
android:toXDelta=”-80″
android:fromYDelta=”30″
android:toYDelta=”300″
android:duration=”2000″ />
<!--
fromXDelta:为动画起始时 X坐标上的位置
toXDelta: 为动画结束时 X坐标上的位置
fromYDelta: 为动画起始时 Y坐标上的位置
toYDelta:为动画结束时 Y坐标上的位置 -->
Rotate:
<rotate
android:interpolator=”@android:anim/accelerate_decelerate_interpolator”
android:fromDegrees=”0″
android:toDegrees=”+350″
android:pivotX=”50%”
android:pivotY=”50%”
android:duration=”3000″ />
<!--
fromDegrees:动画起始时物件的角度
toDegrees:动画结束时物件旋转的角度 可以大于360度
当角度为负数——表示逆时针旋转
当角度为正数——表示顺时针旋转
(负数from——to正数:顺时针旋转)
(负数from——to负数:逆时针旋转)
(正数from——to正数:顺时针旋转)
(正数from——to负数:逆时针旋转)
pivotX;:为动画相对于物件的X、Y坐标的开始位置
pivotY: 为动画相对于物件的X、Y坐标的开始位置
50%为物件的X或Y方向坐标上的中点位置 -->
用Animation子类的构造函数使用动画
Animation anim = AnimationUtils.loadAnimation(mContext, R.anim.rotate);
//监听动画的状态(开始,结束)
anim.setAnimationListener(new EffectAnimationListener());
textWidget = (TextView)findViewById(R.id.text_widget);
textWidget.setText("画面旋转动画效果");
textWidget.startAnimation(anim);
二 Frame Animation(Drawable动画)
Frame Animation是顺序播放事先做好的图像,跟电影类似。不同于animation package,Android SDK提供了另外一个类AnimationDrawable来定义使用Frame Animation。
<?xml version="1.0" encoding="utf-8"?>
<animation-list
xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="true"
>
<item android:drawable="@drawable/p1" android:duration="1000"></item>
<item android:drawable="@drawable/p2" android:duration="1000"></item>
<item android:drawable="@drawable/p3" android:duration="1000"></item>
<item android:drawable="@drawable/p4" android:duration="1000"></item>
<item android:drawable="@drawable/p5" android:duration="1000"></item>
<item android:drawable="@drawable/p6" android:duration="1000"></item>
</animation-list>
使用动画
AnimationDrawable anim = (AnimationDrawable)getResources().
getDrawable(R.drawable.frame);
textWidget = (TextView)findViewById(R.id.text_widget);
textWidget.setText("背景渐变动画效果");
textWidget.setBackgroundDrawable(anim);
anim.start();
这里有点不同的是,利用AnimationDrawable实现动画时,本身并没有提供接口来监听动画的状态(开始,结束),需要自己处理。
二 Property Animation(属性动画)
属性动画,有二个重要的概念:插值器(TimeInterpolator)和估值算法(TypeEvaluator)。
TimeInterpolator为时间插值器,它的作用是根据时间流逝的百分比来计算出当前属性值改变的百分比,系统预置的有 LinearInterpolator(线性插值器:匀速动画)、AccelerateDecelerateInterpolator(加速减速插值器: 动画两头慢中间快)和DecelerateInterpolator(减速插值器:动画越来越慢)等;
TypeEvaluator为类型估值算 法,它的作用是根据当前属性改变的百分比来计算改变后的属性值,系统预置的有IntEvaluator(针对整型属性)、 FloatEvaluator(针对浮点型属性)和ArgbEvaluator(针对Color属性)。
比较常用的几个动画类是:ValueAnimator、ObjectAnimator和AnimatorSet,其中ObjectAnimator继承自 ValueAnimator,AnimatorSet是动画集,可以定义一组动画。
例子如下:
1:改变一个对象(myObject)的 translationY属性,让其沿着Y轴向上平移一段距离:它的高度,该动画在默认时间内完成,动画的完成时间是可以定义的。
ObjectAnimator.ofFloat(myObject, "translationY", -myObject.getHeight()).start();
2:改变一个对象的背景色属性,典型的情形是改变View的背景色,下面的动画可以让背景色在3秒内实现从0xFFFF8080到0xFF8080FF的渐变,并且动画会无限循环而且会有反转的效果。ValueAnimator colorAnim = ObjectAnimator.ofInt(this, "backgroundColor", /*Red*/0xFFFF8080, /*Blue*/0xFF8080FF);
colorAnim.setDuration(3000);
colorAnim.setEvaluator(new ArgbEvaluator());
colorAnim.setRepeatCount(ValueAnimator.INFINITE);
colorAnim.setRepeatMode(ValueAnimator.REVERSE);
colorAnim.start();
3:动画集合,5秒内对View的旋转、平移、缩放和透明度都进行了改变:
AnimatorSet set = new AnimatorSet();
set.playTogether(
ObjectAnimator.ofFloat(myView, "rotationX", 0, 360),
ObjectAnimator.ofFloat(myView, "rotationY", 0, 180),
ObjectAnimator.ofFloat(myView, "rotation", 0, -90),
ObjectAnimator.ofFloat(myView, "translationX", 0, 90),
ObjectAnimator.ofFloat(myView, "translationY", 0, 90),
ObjectAnimator.ofFloat(myView, "scaleX", 1, 1.5f),
ObjectAnimator.ofFloat(myView, "scaleY", 1, 0.5f),
ObjectAnimator.ofFloat(myView, "alpha", 1, 0.25f, 1)
);
set.setDuration(5 * 1000).start();
以上,是根据工作中,常用的一些动画收集汇总的!
今天在一个牛人的 博客看到了,对属性动画原理进行分析:
例子如下:
private void performAnimate() {
ObjectAnimator.ofInt(mButton, "width", 500).setDuration(5000).start();
}
@Override
public void onClick(View v) {
if (v == mButton) {
performAnimate();
}
}
运行效果很差,且不是动画,而是放大!
属性动画的原理:
属性动画要求动画作用的对象提供该属性的get和set方法,属性动画根据你传递的该熟悉的初始值和最终值,以动画的效果多次去调用set方法,每 次传递给set方法的值都不一样,确切来说是随着时间的推移,所传递的值越来越接近最终值。总结一下,你对object的属性xxx做动画,如果想让动画 生效,要同时满足两个条件:
1. object必须要提供setXxx方法,如果动画的时候没有传递初始值,那么还要提供getXxx方法,因为系统要去拿xxx属性的初始值(如果这条不满足,程序直接Crash)
2. object的setXxx对属性xxx所做的改变必须能够通过某种方法反映出来,比如会带来ui的改变啥的(如果这条不满足,动画无效果但不会Crash)
以上条件缺一不可
针对上述问题,Google告诉我们有3中解决方法:
1. 给你的对象加上get和set方法,如果你有权限的话(因为系统提供,不作说明)
2. 用一个类来包装原始对象,间接为其提供get和set方法
3. 采用ValueAnimator,监听动画过程,自己实现属性的改变
用一个类来包装原始对象,间接为其提供get和set方法
private void performAnimate() {
ViewWrapper wrapper = new ViewWrapper(mButton);
wrapper .setWidth(button.getWidth());
ObjectAnimator.ofInt(wrapper, "width", 500).setDuration(5000).start();
}
@Override
public void onClick(View v) {
if (v == mButton) {
performAnimate();
}
}
private static class ViewWrapper {
private View mTarget;
public ViewWrapper(View target) {
mTarget = target;
}
public int getWidth() {
return mTarget.getLayoutParams().width;
}
public void setWidth(int width) {
mTarget.getLayoutParams().width = width;
mTarget.requestLayout();
}
}
采用ValueAnimator,监听动画过程,自己实现属性的改变
首先说说啥是ValueAnimator,ValueAnimator本身不作用于任何对象,也就是说直接使用它没有任何动画效果。它可以对一个值做动画,然后我们可以监听其动画过程,在动画过程中修改我们的对象的属性值,这样也就相当于我们的对象做了动画。
private void performAnimate(final View target, final int start, final int end) {
ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 100);
valueAnimator.addUpdateListener(new AnimatorUpdateListener() {
//持有一个IntEvaluator对象,方便下面估值的时候使用
private IntEvaluator mEvaluator = new IntEvaluator();
@Override
public void onAnimationUpdate(ValueAnimator animator) {
//获得当前动画的进度值,整型,1-100之间
int currentValue = (Integer)animator.getAnimatedValue();
Log.d(TAG, "current value: " + currentValue);
//计算当前进度占整个动画过程的比例,浮点型,0-1之间
float fraction = currentValue / 100f;
//这里我偷懒了,不过有现成的干吗不用呢
//直接调用整型估值器通过比例计算出宽度,然后再设给Button
target.getLayoutParams().width = mEvaluator.evaluate(fraction, start, end);
target.requestLayout();
}
});
valueAnimator.setDuration(5000).start();
}
@Override
public void onClick(View v) {
if (v == mButton) {
performAnimate(mButton, mButton.getWidth(), 500);
}
}
上述代码的动画效果图和采用ViewWrapper是一样的,请参看上图。关于这个ValueAnimator我要再说一下,拿上例来说,它会在 5000ms内将一个数从1变到100,然后动画的每一帧会回调onAnimationUpdate方法,在这个方法里,我们可以获取当前的值 (1-100),根据当前值所占的比例(当前值/100),我们可以计算出Button现在的宽度应该是多少,比如时间过了一半,当前值是50,比例为 0.5,假设Button的起始宽度是100px,最终宽度是500px,那么Button增加的宽度也应该占总增加宽度的一半,总增加宽度是 500-100=400,所以这个时候Button应该增加宽度400*0.5=200,那么当前Button的宽度应该为初始宽度+ 增加宽度(100+200=300)。
有几点是注意的。
1.View动画(渐变动画)的功能是有限的,大家可以尝试使用属性动画
2.为了在各种安卓版本上使用属性动画,你需要采用nineoldandroids,它是GitHub开源项目,jar包和源码都可以在网上下到,如果下不到jar包,我可以发给大家
3.再复杂的动画都是简单动画的合理组合,再加上本文介绍的方法,可以对任何属性作用动画效果,也就是说你几乎可以做出任何动画
4.属性动画中的插值器(Interpolator)和估值器(TypeEvaluator)很重要,它是实现非匀速动画的重要手段,你应该试着搞懂它,最好你还能够自定义它们。