Android中的动画分为视图动画(View Animation)、属性动画(Property Animation)以及Drawable动画。
Android从最初的版本就支持视图动画,视图动画顾名思义,就是应用在视图View上的动画。视图动画的核心类是android/view/animation/Animation,该类是一个抽象类,该类有五个子类,分别是AlphaAnimation、TranslateAnimation、RotateAnimation、ScaleAnimation、AnimationSet。AlphaAnimation可以让View实现透明度渐变效果,TranslateAnimation可以让View实现平移动画效果,RotateAnimation可以让View实现旋转动画效果,ScaleAnimation可以让View实现伸缩动画效果,AnimationSet可以让将多个视图动画组合起来应用到某个View上,从而实现复杂的动画效果。动画既可以用代码实现,也可以用XML文件定义动画。
本文下面的示例代码都是对一个TextView进行的操作,对应的layout文件如下所示:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.ispring.viewanimation.AnimationActivity"> <TextView android:id="@+id/textView" android:text="@string/hello_world" android:layout_width="200dp" android:layout_height="100dp" android:background="#8bc5ba" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:onClick="onClick" android:text="开始" /></RelativeLayout>
说明:下文会涉及各种坐标系,这里先提一个基础知识,下面提及的各种坐标系的都是X正半轴水平向右,Y轴正半轴垂直向下的。
AlphaAnimation
AlphaAnimation可以让View实现透明度渐变效果。其使用方法如下所示:
//1.0表示完全不透明,0.0表示完全透明float fromAlpha = 1.0f;float toAlpha = 0.0f;//1.0 => 0.0表示View从完全不透明渐变到完全透明Animation animation = new AlphaAnimation(fromAlpha, toAlpha);//设置动画持续时间为3000毫秒animation.setDuration(3000);//通过View的startAnimation方法将动画立即应用到View上textView.startAnimation(animation);
界面如下所示:
下面对以上代码进行一下解释:
AlphaAnimation的构造函数方法签名是
public AlphaAnimation (float fromAlpha, float toAlpha)
fromAlpha表示动画开始时View的透明度alpha值,toAlpha表示动画结束时View的透明度alpha值。在以上代码中,我们将fromAlpha设置为1.0,表示动画开始时TextView完全不透明,即完全可见;将toAlpha设置为0.0,表示动画结束时TextView完全透明,即完全不可见。这就实现了TextView从完全可见到完全不可见的透明度渐变效果。
我们还要通过Animation的setDuration方法设置动画的持续时间,单位为毫秒,我们在上面的代码中设置的是3000毫秒,即动画持续三秒。
最后我们调用View的startAnimation方法将动画绑定到TextView上并立即开始动画效果。
由此我们可见,使用视图动画其实比较简单,基本流程是:
- 创建Animation某个子类的实例
- 通过Animation的setDuration方法设置动画持续时间
- 最后通过View的startAnimation方法启动动画
在使用其他视图动画时流程跟上面基本一致,只是最开始动画的构造函数传入的参数不同而已。
之前提到,除了可以用代码创建动画外,还可以用XML文件定义动画,我们可以用下面的XML文件定义上述动画:
<?xml version="1.0" encoding="utf-8"?><alpha xmlns:android="http://schemas.android.com/apk/res/android" android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="3000" />
定义视图动画的XML文件是放在res/anim文件夹下的,此处我设置动画的文件名是alpha.xml,如下图所示:
然后我们可以通过AnimationUtils.loadAnimation()方法根据XML资源文件得到一个Animation对象,如下所示:
Animation animation = AnimationUtils.loadAnimation(this, R.anim.alpha);textView.startAnimation(animation);
当我们需要更改动画效果的参数的时候,我们只需要更新动画XML文件即可,无需更改代码,所以用XML文件定义动画比用代码生成一个动画对象可维护性更好一些。但是有些情况下,我们创建动画的参数可能是在运行时才动态决定的,那这样就无法用XML定义动画了,只能用代码创建动画对象。在后面的文章中,大部分动画都给出了对应的XML文件定义。
TranslateAnimation
TranslateAnimation可以让View实现平移动画效果。
TranslateAnimation有两个常用的构造函数,分别是:
public TranslateAnimation (float fromXDelta, float toXDelta, float fromYDelta, float toYDelta)public TranslateAnimation (int fromXType, float fromXValue, int toXType, float toXValue, int fromYType, float fromYValue, int toYType, float toYValue)
我们分别研究一下这两个构造函数。
public TranslateAnimation (float fromXDelta, float toXDelta, float fromYDelta, float toYDelta)
该构造函数的使用方法如下所示:int fromXDelta = 0;int toXDelta = getResources().getDisplayMetrics().widthPixels / 2;int fromYDelta = 0;int toYDelta = 0;//让动画在水平位置上沿X轴平移toXDelta个像素Animation animation = new TranslateAnimation(fromXDelta, toXDelta, fromYDelta, toYDelta);//设置动画持续时间为3000毫秒animation.setDuration(3000);//通过View的startAnimation方法将动画立即应用到View上textView.startAnimation(animation);
界面如下所示:
下面对以上代码进行一下说明:
fromXDelta 表示动画开始时View相对于原来位置X轴方向的偏移坐标
toXDelta 表示动画结束时View相对于原来位置X轴方向的偏移坐标
fromYDelta 表示动画开始时View相对于原来位置Y轴方向的偏移坐标
toYDelta 表示动画结束时View相对于原来位置Y轴方向的偏移坐标
也就是说,构造函数里面的这四个delta分量都是相对于View原来位置的相对坐标偏移分量,这里所说的“View原来位置”指的是View在动画开始前的初始位置。我们在示例中fromYDelta和toYDelta 都设置为0,表示TextView不会在Y轴方向上平移。fromXDelta 设置为0表示动画开始时,TextView的X坐标与初始的X坐标一致。toXDelta 表示了TextView向右偏移的距离。
实际上,对该构造函数,Android没有提供对应的XML文件定义,但是下面的构造函数有相应的XML文件定义。
public TranslateAnimation (int fromXType, float fromXValue, int toXType, float toXValue, int fromYType, float fromYValue, int toYType, float toYValue)
该构造函数相比于之前的构造函数来说更加灵活,使用方法如下所示://设置fromXint fromXType = Animation.ABSOLUTE;float fromXValue = textView.getX();//设置toXint toXType = Animation.RELATIVE_TO_PARENT;float toXValue = 0.5f;//设置fromYint fromYType = Animation.ABSOLUTE;float fromYValue = textView.getY();//设置toYint toYType = Animation.RELATIVE_TO_SELF;float toYValue = 3.0f;//创建动画Animation animation = new TranslateAnimation( fromXType, fromXValue, toXType, toXValue, fromYType, fromYValue, toYType, toYValue);//设置动画持续时间为3000毫秒animation.setDuration(3000);//通过View的startAnimation方法将动画立即应用到View上textView.startAnimation(animation);
界面如下所示:
下面对以上代码进行说明:
该构造函数有八个参数,其中可以分为四组,(fromXType、fromXValue)决定了动画开始时View的X坐标,(toXType、toXValue)决定了动画结束时View的X坐标,(fromYType、fromYValue)决定了动画开始时View的Y坐标,(toYType、toYValue)决定了动画结束时View的Y坐标。这四组参数就完整地定义了平移动画开始和结束时View的坐标位置。
由于这四组参数参数取值类似,所以我们主要研究其中一组即可,我们以fromXType和fromXValue进行说明,fromXType的取值类型决定了如何设置fromXValue的值。fromXType的取值有三种,分别是:ABSOLUTE、RELATIVE_TO_PARENT和RELATIVE_TO_SELF。
ABSOLUTE
当fromXType取值为ABSOLUTE时,表示fromXValue的值是在该View的父控件的坐标系的绝对值,比如fromXValue为200,表示动画开始时,View的左侧到其父控件左侧的距离是200个像素。RELATIVE_TO_PARENT
当fromXType取值为RELATIVE_TO_PARENT时,表示fromXValue的值是相对于其父控件尺寸的百分比。比如fromXValue为0,表示动画开始时,View的左侧紧靠父控件的左侧;fromXValue为0.5时,表示动画开始时,View的左侧位置在父控件水平方向中间的位置;fromXValue为1时,表示动画开始时,View的左侧位置与父控件的右侧位置完全重合。RELATIVE_TO_SELF
当fromXType取值为RELATIVE_TO_SELF时,表示fromXValue的值是相对于其自身尺寸的百分比。比如fromXValue为0,表示动画开始时,View的X坐标和初始位置的X坐标相同;fromXValue为0.5时,表示动画开始时,View的左侧位置在初始View状态下水平方向中间的位置,即向右偏移了View宽度的一半;fromXValue为1时,表示动画开始时,View的左侧位置正好与初始View状态下的右侧位置重合,即向右偏移了正好View的宽度大小的距离。
有了以上理论基础,我们再看一下我们上面的代码。
设置fromX
int fromXType = Animation.ABSOLUTE;float fromXValue = textView.getX();
我们将fromXType设置为ABSOLUTE,然后将fromXValue的值设置为textView.getX(),这样的意义是动画开始时,TextView的X坐标与TextView初始状态下X坐标相同。
设置toX
int toXType = Animation.RELATIVE_TO_PARENT;float toXValue = 0.5f;
我们将toXType设置为RELATIVE_TO_PARENT,将toXValue设置为0.5,表示动画结束时,TextView的左侧将会处于其父控件RelativeLayout的水平中间位置。
设置fromY
int fromYType = Animation.ABSOLUTE;float fromYValue = textView.getY();
将fromYType设置为ABSOLUTE,将fromYValue设置为textView.getY(),这样的意义是动画开始时,TextView的Y坐标与TextView初始状态下Y坐标相同。
设置toY
int toYType = Animation.RELATIVE_TO_SELF;float toYValue = 3.0f;
我们将toYType设置为RELATIVE_TO_SELF,将toYValue设置为为3,表示当动画结束时,TextView的Y坐标将变成其高度的三倍。
我们设置的fromX和toX两组参数会使得TextView在X水平方向上向右滑动;fromY和toY两组参数会使得TextView在Y垂直方向上向下滑动,大家可以仔细观看上面的动态图理解一下。
上述动画对应的XML文件如下所示:
<?xml version="1.0" encoding="utf-8"?><translate xmlns:android="http://schemas.android.com/apk/res/android" android:fromXDelta="0" android:toXDelta="50%p" android:fromYDelta="0" android:toYDelta="300%" android:duration="3000"/>
以上XML文件中fromXDelta、toXDelta、fromYDelta、toYDelta四个参数都是float类型的参数,这几个值可以以%结尾,也可以以%p结尾,也可以没有其他额外结尾。
无结尾
fromXDelta和fromYDelta都只是一个简单的float值,没有其他额外的结尾,这样的值表示的意思是该值对应的类型是Animation.ABSOLUTE,即表示的绝对值,即android:fromXDelta="0"
与以下代码等价:int fromXType = Animation.ABSOLUTE; float fromXValue = 0;
以%p结尾
toXDelta的值是50%p,以%p结尾,此处的p是Parent的缩写,说明值的类型是Animation.RELATIVE_TO_PARENT,即该值表示相对于其父控件宽度的50%,android:toXDelta="50%p"
等价于以下代码:int toXType = Animation.RELATIVE_TO_PARENT;float toXValue = 0.5f;
以%结尾
toYDelta的值是300%,以%结尾,此处的%是相对于控件自身的,即值对应的类型是Animation.RELATIVE_TO_SELF,android:toYDelta="300%"
等价于以下代码:int toYType = Animation.RELATIVE_TO_SELF;float toYValue = 3.0f;
RotateAnimation
RotateAnimation可以让View在XY平面内实现旋转动画效果。
RotateAnimation有三个常用的构造函数,分别是:
public RotateAnimation (float fromDegrees, float toDegrees)public RotateAnimation (float fromDegrees, float toDegrees, float pivotX, float pivotY)public RotateAnimation (float fromDegrees, float toDegrees, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)
旋转动画需要两种类型的参数:动画的旋转轴以及动画的旋转角度。RotateAnimation的三个构造函数的主要区别在于确定动画旋转轴的参数不同,我们具体看一下。
public RotateAnimation (float fromDegrees, float toDegrees)
该构造函数只需要传入动画开始时的旋转角度以及动画结束时的旋转角度即可,toDegrees与fromDegrees的差值即旋转过的角度,不需要额外传入参数设置旋转轴。这种情况下,动画的旋转轴就是View的左上角点。该构造函数使用方法如下所示://以View左上角为旋转轴,创建旋转60度的动画Animation animation = new RotateAnimation(0, 60);//设置动画持续时间animation.setDuration(3000);//通过View的startAnimation方法将动画立即应用到View上textView.startAnimation(animation);
界面如下所示:
我们看到,TextView以其左上角点为旋转轴沿着顺时针方向旋转了60度。
上述动画对应的XML文件如下所示:
<?xml version="1.0" encoding="utf-8"?><rotate xmlns:android="http://schemas.android.com/apk/res/android" android:fromDegrees="0" android:toDegrees="60" android:duration="3000"/>
public RotateAnimation (float fromDegrees, float toDegrees, float pivotX, float pivotY)
很多情况下用View的左上角点作为旋转轴不能满足实际需求,那么我们就可以利用该构造函数传入旋转轴的位置坐标(pivotX,pivotY)。需要说明的是,此处的坐标(pivotX,pivotY)指的是View自身的局部坐标系中的坐标。所谓的View自身的局部坐标系就是以View自身的左上角为坐标原点的坐标系。该构造函数的使用方法如下所示://以View中心点作为旋转轴,创建旋转60度的动画float pivotX = textView.getWidth() / 2;float pivotY = textView.getHeight() / 2;Animation animation = new RotateAnimation(0, 90, pivotX, pivotY);//设置动画持续时间animation.setDuration(3000);//通过View的startAnimation方法将动画立即应用到View上textView.startAnimation(animation);
界面如下所示:
在上面的代码中,我们将TextView长度的一半作为旋转轴的pivotX,将TextView高度的一半作为旋转轴的pivotY,这样TextView就以自身的中心点作为旋转轴顺时针旋转了90度。
假设TextView的getWidth()和getHeight()返回的宽度、高度分别是是200像素和100像素,那么上述动画对应的XML文件如下所示:
<?xml version="1.0" encoding="utf-8"?><rotate xmlns:android="http://schemas.android.com/apk/res/android" android:fromDegrees="0" android:toDegrees="90" android:pivotX="100" android:pivotY="50" android:duration="3000"/>
此处XML文件中pivotX和pivotY的取值规则与之前提到的Translate动画的XML文件中fromXDelta等参数的取值规则相同。此处XML文件中pivotX和pivotY的取值都是简单的float类型,表示该值的类型是Animation.ABSOLUTE。 其实此处如果将pivotX和pivotY的值都设置为50%也能达到以TextView中心点旋转的目的,以%结尾表示值的类型是Animation.RELATIVE_TO_SELF,50%表示相对于TextView自身的中心点。
public RotateAnimation (float fromDegrees, float toDegrees, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)
该构造函数是最灵活的一种方式。pivotXType和pivotYType可取值ABSOLUTE或RELATIVE_TO_SELF或RELATIVE_TO_PARENT,其取值决定了对应的pivotXValue和pivotYValue的取值意义。该构造函数中的旋转轴坐标的取值规则与上面介绍的TranslateAnimation的最后一个构造函数中坐标的取值规则完全一样,在此不再赘述。此处给出一段示例代码:
//以View的父控件中心点作为旋转轴,创建旋转360度的动画int pivotXType = Animation.RELATIVE_TO_PARENT;float pivotXValue = 0.5f;int pivotYType = Animation.RELATIVE_TO_PARENT;float pivotYValue = 0.5f;Animation animation = new RotateAnimation( 0, 360, pivotXType, pivotXValue, pivotYType, pivotYValue);//设置动画持续时间animation.setDuration(3000);//通过View的startAnimation方法将动画立即应用到View上textView.startAnimation(animation);
界面如下所示:
上面我们将pivotXType和pivotYType的值都设置为RELATIVE_TO_PARENT,然后将pivotXValue和pivotYValue都设置为0.5,这样TextView的旋转动画将会以其父控件RelativeLayout的中心点作为旋转轴旋转360度。
上述动画对应的XML文件如下所示:
<?xml version="1.0" encoding="utf-8"?><rotate xmlns:android="http://schemas.android.com/apk/res/android" android:fromDegrees="0" android:toDegrees="360" android:pivotX="50%p" android:pivotY="50%p" android:duration="3000"/>
此处XML文件中pivotX和pivotY的取值规则与之前提到的Translate动画的XML文件中fromXDelta等参数的取值规则相同。pivotX和pivotY的值都以%p结尾,表示取值类型是Animation.RELATIVE_TO_PARENT,50%p即表示相对于父控件的中心。
ScaleAnimation
ScaleAnimation可以让View实现伸缩动画效果,它有三个常用的构造函数,分别是:
public ScaleAnimation (float fromXScale, float toScaleX, float fromYScale, float toScaleY)public ScaleAnimation (float fromXScale, float toScaleX, float fromYScale, float toScaleY, float pivotX, float pivotY)public ScaleAnimation (float fromXScale, float toScaleX, float fromYScale, float toScaleY, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)
ScaleAnimation需要两种类型的参数:缩放动画的中心点以及XY两个方向的缩放比例。View会基于动画的缩放中心按照指定的缩放比例进行缩放。ScaleAnimation的三个构造函数的主要区别在于确定动画的缩放中心,我们具体研究一下。
public ScaleAnimation (float fromXScale, float toScaleX, float fromYScale, float toScaleY)
该构造函数只需要传入View在X轴、Y轴上动画开始以及结束的缩放比例,fromXScale和toScaleX分别表示动画开始和结束时X轴的缩放比例,fromYScale和toScaleY表示动画开始和结束时Y轴的缩放比例。不需要额外传入参数设置动画的缩放中心。这种情况下,动画的缩放中心就是View的左上角点。该构造函数的使用方法如下所示:
//以View左上角作为缩放中心,水平方向扩大一倍,垂直方向缩小为原来的一半float fromXScale = 1.0f;float toScaleX = 2.0f;float fromYScale = 1.0f;float toScaleY = 0.5f;Animation animation = new ScaleAnimation(fromXScale, toScaleX, fromYScale, toScaleY);//设置动画持续时间animation.setDuration(3000);//通过View的startAnimation方法将动画立即应用到View上textView.startAnimation(animation);
界面如下所示:
如上图所示,TextView以其左上角点作为缩放中心,在X轴方向扩大了一倍,在Y轴方向缩减为原来的一半。
上述动画对应的XML文件如下所示:
<?xml version="1.0" encoding="utf-8"?><scale xmlns:android="http://schemas.android.com/apk/res/android" android:fromXScale="1" android:toXScale="2" android:fromYScale="1" android:toYScale="0.5" android:duration="3000"/>
public ScaleAnimation (float fromXScale, float toScaleX, float fromYScale, float toScaleY, float pivotX, float pivotY)
很多情况下用View的左上角点作为缩放中心不能满足实际需求,那么我们就可以利用该构造函数传入动画缩放中心的位置坐标(pivotX,pivotY)。需要说明的是,此处的坐标(pivotX,pivotY)指的是View自身的局部坐标系中的坐标。所谓的View自身的局部坐标系就是以View自身的左上角为坐标原点的坐标系。该构造函数的使用方法如下所示:
//以View中心点作为缩放中心,水平方向和垂直方向都缩小为原来的一半float fromXScale = 1.0f;float toScaleX = 0.5f;float fromYScale = 1.0f;float toScaleY = 0.5f;float pivotX = textView.getWidth() / 2;float pivotY = textView.getHeight() / 2;Animation animation = new ScaleAnimation( fromXScale, toScaleX, fromYScale, toScaleY, pivotX, pivotY); //设置动画持续时间 animation.setDuration(3000); //通过View的startAnimation方法将动画立即应用到View上 textView.startAnimation(animation);
界面如下所示:
在上面的代码中,我们将TextView的中心点作为动画的缩放中心,如上图所示,TextView基于该缩放中心在水平方向和垂直方向都缩小为原来的一半。
假设TextView的getWidth()和getHeight()返回的宽度、高度分别是是200像素和100像素,那么上述动画对应的XML文件如下所示:
<?xml version="1.0" encoding="utf-8"?><scale xmlns:android="http://schemas.android.com/apk/res/android" android:fromXScale="1" android:toXScale="0.5" android:fromYScale="1" android:toYScale="0.5" android:pivotX="100" android:pivotY="50" android:duration="3000"/>
此处XML文件中pivotX和pivotY的取值规则与之前提到的Translate动画的XML文件中fromXDelta等参数的取值规则相同。此处XML文件中pivotX和pivotY的取值都是简单的float类型,表示该值的类型是Animation.ABSOLUTE。 其实此处如果将pivotX和pivotY的值都设置为50%也能达到以TextView中心点缩放的目的,详见下文。
public ScaleAnimation (float fromXScale, float toScaleX, float fromYScale, float toScaleY, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)
该构造函数是最灵活的一种方式。pivotXType和pivotYType可取值ABSOLUTE或RELATIVE_TO_SELF或RELATIVE_TO_PARENT,其取值决定了对应的pivotXValue和pivotYValue的取值意义。该构造函数中的旋转轴坐标的取值规则与上面介绍的TranslateAnimation的最后一个构造函数中坐标的取值规则完全一样,在此不再赘述。此处给出一段示例代码:
//以View中心点作为缩放中心,水平方向和垂直方向都缩小为原来的一半float fromXScale = 1.0f;float toScaleX = 0.5f;float fromYScale = 1.0f;float toScaleY = 0.5f;int pivotXType = Animation.RELATIVE_TO_SELF;float pivotXValue = 0.5f;int pivotYType = Animation.RELATIVE_TO_SELF;float pivotYValue = 0.5f;Animation animation = new ScaleAnimation( fromXScale, toScaleX, fromYScale, toScaleY, pivotXType, pivotXValue, pivotYType, pivotYValue);//设置动画持续时间animation.setDuration(3000);//通过View的startAnimation方法将动画立即应用到View上textView.startAnimation(animation);
上面的代码实现的效果跟第二个构造函数中给出的代码实现的效果完全一致,只不过这次设置了pivotXType和pivotYType,并将其值都设置为RELATIVE_TO_SELF,且pivotXValue和pivotYValue都设置为0.5,这样就将TextView的中心点设置成了动画的缩放中心。效果参考第二个构造函数中的效果图。
上述动画对应的XML文件如下所示:
<?xml version="1.0" encoding="utf-8"?><scale xmlns:android="http://schemas.android.com/apk/res/android" android:fromXScale="1" android:toXScale="0.5" android:fromYScale="1" android:toYScale="0.5" android:pivotX="50%" android:pivotY="50%" android:duration="3000"/>
以%结尾表示值的类型是Animation.RELATIVE_TO_SELF,此处pivotX和pivotY都取值50%,表示相对于TextView自身的中心点进行缩放。如果以%p结尾,那么表示值的类型是Animation.RELATIVE_TO_PARENT。
希望本文对大家理解Android中的视图动画有所帮助!