Android动画可以分为三种:
View动画,帧动画和属性动画。
其实帧动画也属于View动画,只不过它的平移,旋转等常用的View动画在表现上略有不同而已。View动画通过对场景里的对象不断做图像变换(平移,缩放,旋转,透明度)从而产生动画效果,他是一种渐进式动画,并且View动画支持自定义。帧动画通过顺序播放一系列图像从而产生动画效果,可以简单理解为图片切换动画,很显然,如果图片过大就会导致OOM。属性动画通过动态的改变对象的属性从而达到动画效果,属性动画为API 11 的新特性,在低版本无法直接使用属性动画,但我们仍然可以通过兼容库来使用它。
(1)View动画
View动画的四种变换效果对应着Animation的四个子类:TranslateAnimation,ScaleAnimation, RotateAnimation 和 AlphaAnimation.
要使用View动画,首先要创建动画的XML文件,这个文件的路径为:res/anim/filename.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>
TranslateAnimation:
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500"
android:fromXDelta="100"
android:fromYDelta="0"
android:interpolator="@android:anim/cycle_interpolator"
android:toXDelta="0"
android:toYDelta="0" />
ScaleAnimation:
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500"
android:fromXScale="0.0"
android:fromYScale="0.0"
android:toXScale="1.5"
android:toYScale="1.5"
android:interpolator="@android:anim/decelerate_interpolator"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="1"
android:repeatMode="reverse"
android:startOffset="0"
/>
RotateAnimation:
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500"
android:fromDegrees="0"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="-360" />
AlphaAnimation:
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500"
android:fillAfter="false"
android:fromAlpha="1.0"
android:toAlpha="0.0" />
也可以在代码中定义动画,例子如下:
/*
在代码中定义AlphaAnimation动画
*/
AlphaAnimation alphaAnimation = new AlphaAnimation(0,1);
alphaaAnimation.setDuration(300);
mButton.startAnimation(alphaAnimation);//为mButtond设置AlphaAnimation动画
剩下三个View动画在代码中的定义与上图代码大同小异。
自定义View动画:定义自定义动画需要继承Animation这个抽象类,然后重写它的initalize和applyTransformation方法,在initalize方法中做一些初始化工作,在applyTransformation中进行相应的矩阵变换。在实际开发中很少用到自定义View动画,所以我们也就不在这深入分析自定义View动画了。
(2)帧动画
在drawable文件夹下新建一个文件frame.xml,而不是anim文件夹
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">//oneshot:是否只播放一次
<item
android:drawable="@mipmap/lottery_1"
android:duration="200"/>//duration:这一帧持续的时间
<item
android:drawable="@mipmap/lottery_2"
android:duration="200"/>
<item
android:drawable="@mipmap/lottery_3"
android:duration="200"/>
</animation-list>
在代码中定义帧动画:
AnimationDrawable anim = new AnimationDrawable();
for (int i = 1; i <= 6; i++) {
int id = getResources().getIdentifier("lottery_" + i, "mipmap", getPackageName());
Drawable drawable = getResources().getDrawable(id);
anim.addFrame(drawable, 200);//添加帧
}
anim.setOneShot(false);//设置为循环播放
imageView.setImageDrawable(anim);
anim.start();
(3)属性动画
Android开发团队决定在3.0版本当中引入属性动画这个功能。属性动画机制已经不再是针对于View来设计的了,也不限定于只能实现移动、缩放、旋转和淡入淡出这几种动画操作,同时也不再只是一种视觉上的动画效果了。它实际上是一种不断地对值进行操作的机制,并将值赋值到指定对象的指定属性上,可以是任意对象的任意属性。所以我们仍然可以将一个View进行移动或者缩放,但同时也可以对自定义View中的Point对象进行动画操作了。我们只需要告诉系统动画的运行时长,需要执行哪种类型的动画,以及动画的初始值和结束值,剩下的工作就可以全部交给系统去完成了。
既然属性动画的实现机制是通过对目标对象进行赋值并修改其属性来实现的,那么之前所说的按钮显示的问题也就不复存在了,如果我们通过属性动画来移动一个按钮,那么这个按钮就是真正的移动了,而不再是仅仅在另外一个位置绘制了而已。
ValueAnimator
ValueAnimator是整个属性动画机制当中最核心的一个类,前面我们已经提到了,属性动画的运行机制是通过不断地对值进行操作来实现的,而初始值和结束值之间的动画过渡就是由ValueAnimator这个类来负责计算的。它的内部使用一种时间循环的机制来计算值与值之间的动画过渡,我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果。除此之外,ValueAnimator还负责管理动画的播放次数、播放模式、以及对动画设置监听器等,确实是一个非常重要的类。
想要将一个值从0平滑过渡到1,时长300毫秒,可以这样写:
ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
anim.setDuration(300);
anim.start();
调用ValueAnimator的ofFloat()方法就可以构建出一个ValueAnimator的实例,ofFloat()方法当中允许传入多个float类型的参数,这里传入0和1就表示将值从0平滑过渡到1,然后调用ValueAnimator的setDuration()方法来设置动画运行的时长,最后调用start()方法启动动画。
怎样才能知道这个动画是不是已经真正运行了呢?这就需要借助监听器来实现了,如下所示:
ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
anim.setDuration(300);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float currentValue = (float) animation.getAnimatedValue();
Log.d("TAG", "cuurent value is " + currentValue);
}
});
anim.start();
这里我们通过addUpdateListener()方法来添加一个动画的监听器,在动画执行的过程中会不断地进行回调,我们只需要在回调方法当中将当前的值取出并打印出来,就可以知道动画有没有真正运行了。
ObjectAnimator
相比于ValueAnimator,ObjectAnimator可能才是我们最常接触到的类,因为ValueAnimator只不过是对值进行了一个平滑的动画过渡,但我们实际使用到这种功能的场景好像并不多。而ObjectAnimator则就不同了,它是可以直接对任意对象的任意属性进行动画操作的,比如说View的alpha属性。
不过虽说ObjectAnimator会更加常用一些,但是它其实是继承自ValueAnimator的,底层的动画实现机制也是基于ValueAnimator来完成的,因此ValueAnimator仍然是整个属性动画当中最核心的一个类。那么既然是继承关系,说明ValueAnimator中可以使用的方法在ObjectAnimator中也是可以正常使用的,它们的用法也非常类似,这里如果我们想要将一个TextView在5秒中内从常规变换成全透明,再从全透明变换成常规,就可以这样写:
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);
animator.setDuration(5000);
animator.start();
可以看到,我们还是调用了ofFloat()方法来去创建一个ObjectAnimator的实例,只不过ofFloat()方法当中接收的参数有点变化了。这里第一个参数要求传入一个object对象,我们想要对哪个对象进行动画操作就传入什么,这里我传入了一个textview。第二个参数是想要对该对象的哪个属性进行动画操作,由于我们想要改变TextView的不透明度,因此这里传入"alpha"。后面的参数就是不固定长度了,想要完成什么样的动画就传入什么值,这里传入的值就表示将TextView从常规变换成全透明,再从全透明变换成常规。之后调用setDuration()方法来设置动画的时长,然后调用start()方法启动动画。
其它的用法我们就可以举一反三了,那比如说我们想要将TextView进行一次360度的旋转,就可以这样写:
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "rotation", 0f, 360f);
animator.setDuration(5000);
animator.start();
下面是一个动画集合,5秒内对View的旋转,平移,缩放和透明度都进行了改变:
AnimationSet set = new AnimatiorSet();
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();
属性动画除了通过代码实现以外,还可以通过XML来定义。属性动画需要定义在res/animator的目录下,他的语法如下:
<set
android:ordering=["together"|"sequentially"]>
<objectAnimator
android:prooertyName="String"
android:duration="int"
android:valueFrom="float | int | color"
android:startOffset="int"
android:repetCount="”int"
android:repeatMode["restart" | "reverse"]
android:valueType=["intType" | "floatType"]/>
<animator
android:duration="int"
android:valueFrom="float | int |color"
android:valueTo="float | int |color"
android:startOffset="int"
android:repeatCount="int"
android:repeatMode=["restart" | "reverse"]
android:valueType=["intType" | "floatType]
<set>
...
</set>
</set>
<ObjectAnimator>标签中各个属性的含义:
android:propertyName--表示属性动画的作用对象的属性的名称;
android:duration--表示动画的时长;
android:valueFrom--表示属性的起始值;
android:valueTo--表示属性的结束值;
android:startOffset--表示动画的延迟实践,当动画开始后,需要延迟多少毫秒才会真正播放此动画;
android:repeatCount--表示动画的重复次数;
android:repeatMode--表示动画的重复模式;
android:valueType--表示android:propertyName所指定的属性的类型,有“intType”和“floatType”两个可选项,分别表示属性的类型为整数和浮点型。另外如果android:properName所指定的属性表示的是颜色,那么不需要指定android:valueType,系统会自动对颜色类型的属性做处理。