android开发中用到的动画实现方式有三种,即View动画、Drawable动画以及属性动画三种动画的实现方式,关于这些动画的实现方式网上很多文章都总结的很详细了,写这篇文章完全是为了自己总结记录,而且本文不会去追究代码细节的问题,就单单总结下怎么用的问题,具体代码细节的话,请参考本文的参考文献。
View动画的实现是通过View控件的setAnimation来设置动画,可以设置的动画有限,只有以下四种
四种动画的作用看名字应该就清楚了,这里以RotateAnimation为例来说说使用View动画的两种方式
第一种是通过xml的方式来实现(三种动画实现方式都可以通过xml配置的方式来实现),在res/anim目录下创建一个view_animation_rotate.xml 内容如下
<!--
* android:fromDegrees="-50":动画开始执行时的控件起始状态的角度;
* android:toDegrees="360":动画结束执行时的控件结束状态的角度;
* android:pivotX="50%":旋转动画的中心点的X轴方向的横坐标,Value正值(例如50%)时,意思是相对于控件的原始位置往右方向的50%控件宽度的位置为横坐标,
* 若Value为负值(例如-50%),则表示往左方向;当Value为数值时,则代表相对于屏幕的(px)像素值;
* android:pivotY="50%":旋转动画的中心店的Y轴方向的纵坐标,原理同上;
* android:startOffset="1000":动画执行前的延迟时间;
* android:fillAfter="true":当Value为true,表示动画执行结束后停留在结束后的状态;
* android:duration="2500":设置每一次动画持续的时间值,单位为毫秒(ms);
* android:repeatCount="5":设置动画重复的次数;
* android:repeatMode="reverse":设置动画重复的模式:
* reverse为0.0 -> 1.0 -> 0.0,动画反复执行;
* restart为0.0 -> 1.0, 0.0 -> 1.0,动画每次都重新开始执行
-->
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromDegrees="520"
android:toDegrees="3600"
android:pivotX="50%"
android:pivotY="50%"
android:startOffset="1000"
android:fillAfter="true"
android:duration="2500"
android:repeatCount="4"
android:repeatMode="reverse"
/>
定义好xml后,便可通过AnimationUtils类来加载xml生成一个动画对象,注意这个AnimationUtils类不是我们自己定义的类,而是Android Sdk提供的android.view.animation包中的类。
/**
* xml文件加载图片旋转(Rotate)动画
*/
RotateAnimation mAnimation = AnimationUtils.loadAnimation(this, R.anim.view_animation_rotate);
这里生成了一个RotateAnimation的对象,调用view.setAnimation(mAnimation)便设置好了view控件的动画。
当然另外一种实现ViewAnimation的方法就是直接通过new RotateAnimation的方式实现,并且在新建的时候传入基本动画参数。
/**
* 代码创建图片旋转(Rotate)动画
* mAnimation = new RotateAnimation(fromDegrees, toDegrees, pivotXType, pivotXValue, pivotYType, pivotYValue);
* fromDegrees:动画开始执行时的控件起始状态的角度;
* toDegrees:动画结束执行时的控件结束状态的角度;
* pivotXType:动画在X轴相对于物件位置类型 ,分为RELATIVE_TO_SELF、RELATIVE_TO_PARENT和ABSOLUTE三种类型:
* 1、RELATIVE_TO_SELF:相对于控件自身;
* 2、RELATIVE_TO_PARENT:相对于父控件;
* 3、ABSOLUTE:绝对坐标;
* pivotXValue:动画开始执行时X轴方向的的起始位置,当位置类型为RELATIVE_TO_SELF时,Value取0.0f~1.0f之间,当位置类型为RELATIVE_TO_PARENT或ABSOLUTE时,Value使用(px)像素值;
* pivotYType:动画在Y轴相对于物件位置类型 ,分为RELATIVE_TO_SELF、RELATIVE_TO_PARENT和ABSOLUTE三种类型;
* pivotYValue:旋转动画的中心点的Y轴方向的纵坐标,原理同上;
*/
//mAnimation = new RotateAnimation(fromDegrees, toDegrees)
//mAnimation = new RotateAnimation(fromDegrees, toDegrees, pivotX, pivotY)
RotateAnimation mAnimation = new RotateAnimation(-50f, 360f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
mAnimation.setDuration(2000);
到这类两种实现View动画的方式就说清楚了,当然我们可能有将四种View动画方式结合起来使用,这个需求也好办,可通过AnimationSet这个动画集合类来实现,也可以在通过在res/anim目录下的xml文件中配置多个动画的方式来实现,这里就不展开说明了。
Drawable动画名称来自于实现Drawable动画的xml文件时放在res/drawable目录中的,比如我们要实现一个机器人走动的动画,那么便可在drawable中放置机器人走动的图片
然后在res/drawable下创建drawable_animation_robot.xml文件,内容如下
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="@drawable/drawable_animation01" android:duration="80"/>
<item android:drawable="@drawable/drawable_animation02" android:duration="80"/>
<item android:drawable="@drawable/drawable_animation03" android:duration="80"/>
<item android:drawable="@drawable/drawable_animation04" android:duration="80"/>
<item android:drawable="@drawable/drawable_animation05" android:duration="80"/>
<item android:drawable="@drawable/drawable_animation06" android:duration="80"/>
<item android:drawable="@drawable/drawable_animation07" android:duration="80"/>
<item android:drawable="@drawable/drawable_animation08" android:duration="80"/>
<item android:drawable="@drawable/drawable_animation09" android:duration="80"/>
<item android:drawable="@drawable/drawable_animation10" android:duration="80"/>
<item android:drawable="@drawable/drawable_animation11" android:duration="80"/>
<item android:drawable="@drawable/drawable_animation12" android:duration="80"/>
<item android:drawable="@drawable/drawable_animation13" android:duration="80"/>
<item android:drawable="@drawable/drawable_animation14" android:duration="80"/>
<item android:drawable="@drawable/drawable_animation15" android:duration="80"/>
<item android:drawable="@drawable/drawable_animation16" android:duration="80"/>
animation-list>
设置好xml后,便可通过下面代码去获得Drawable动画
//设置背景
view.setBackgroundResource(R.drawable.drawable_animation_robot);
//获取当前的背景
mAnimationDrawable = (AnimationDrawable) view.getBackground();
通过以下代码便可以开启动画或者关闭动画
//开启动画
mAnimationDrawable.start();
//关闭动画
mAnmationDrawable.stop();
到这类Drawable动画就算是说清楚了。
属性动画是三种动画实现里最复杂的也是最灵活的,它通过去设置控件的属性从而实现动画效果,与属性动画相关且的有以下一些类
上面的这些类在实现属性动画时会被经常用到,下面来进行分别讲解。
3.1 ObjectAnimator 、 ValueAnimator 、 AnimatorSet这几个类的使用
从以上类中可以看出动画执行类主要有两个,分别是ObjectAnimator和ValueAnimator,其主要区别在于ObjectAnimator在实现动画的时候需要首先指定动画属性,而ValueAnimator则不需要,ValueAnimator是在addUpdateListener中通过set方法去指定属性。
ObjectAnimator实现动画
ObjectAnimator
.ofFloat(view, "rotationY", 0.0F, 360.0F)//指定了属性rotationY
.setDuration(500)
.start();
ValueAnimator实现动画
ValueAnimator animator = ValueAnimator.ofFloat(0, mScreenHeight - mBlueBall.getHeight());
animator.setTarget(mBlueBall);
animator.setDuration(1000).start();
animator.addUpdateListener(new AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
//在addUpdateListener中通过set方法指定属性
mBlueBall.setTranslationY((Float) animation.getAnimatedValue());
}
});
这里我们看到无论是使用ObjectAnimator还是ValueAnimator这里都是对一个属性进行的动画操作,那么如果要同时操作几个属性动画呢?当然我们可以使用AnimatorSet类去实现,但是如果我们不使用AnimatorSet类呢?
针对ObjectAnimator可以使用addUpdateListener的方式实现
ObjectAnimator anim = ObjectAnimator
.ofFloat(view, "zhy", 1.0F, 0.0F)
.setDuration(500);
anim.start();
anim.addUpdateListener(new AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
float cVal = (Float) animation.getAnimatedValue();
view.setAlpha(cVal);
view.setScaleX(cVal);
view.setScaleY(cVal);
}
});
这里的缺点很明显,就是三个属性,我们设置的变化参数却只有一个,于是针对ObjectAnimator我们可以使用PropertyValuesHolder类来完成多属性动画操作,来解决这个问题
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("alpha", 1f, 0f, 1f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f);
PropertyValuesHolder pvhZ = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f);
ObjectAnimator.ofPropertyValuesHolder(view, pvhX, pvhY,pvhZ).setDuration(1000).start();
这里针对多属性,便可以有有多个变化参数去设置动画效果。
ValueAnimator实现多属性动画操作同样的可以使用addUpdateListener以及PropertyValuesHolder两种方法。
当然实现多属性动画操作,还可以使用AniamtorSet这个类来实现
AnimatorSet实现动画集合
使用AnimatorSet这个类可以规定动画的执行先后顺序,各自的执行时间等,使用起来特别灵活
float cx = mBlueBall.getX();
ObjectAnimator anim1 = ObjectAnimator.ofFloat(mBlueBall, "scaleX", 1.0f, 2f);
ObjectAnimator anim2 = ObjectAnimator.ofFloat(mBlueBall, "scaleY", 1.0f, 2f);
ObjectAnimator anim3 = ObjectAnimator.ofFloat(mBlueBall, "x", cx , 0f);
ObjectAnimator anim4 = ObjectAnimator.ofFloat(mBlueBall, "x", cx);
/**
* anim1,anim2,anim3同时执行
* anim4接着执行
*/
AnimatorSet animSet = new AnimatorSet();
animSet.play(anim1).with(anim2);
animSet.play(anim2).with(anim3);
animSet.play(anim4).after(anim3);
animSet.setDuration(1000);
animSet.start();
3.2 AnimatorInflater类的使用
前面讲View动画和Drawable动画的时候都提到了xml来实现动画的方式,而属性动画也可以通过xml的方式下来实现动画效果,其就是借助了AnimatorInflater这个类来实现。
AnimatorInflater类加载额xml文件放在res/animator/目录下,这里创建一个rotation.xml文件,内容为
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:propertyName="rotationX"
android:duration="1000"
android:valueType="floatType"
android:valueFrom="0.0"
android:valueTo="360.0">
objectAnimator>
然后借助AnimatorInflater类来加载xml动画
Animator animator = AnimatorInflater.loadAnimator(context, R.animator.rotation);
animator.setTarget(view);
animator.setDuration(2000);
animator.setInterpolator(new LinearInterpolator());
animator.start();
这样便通过使用AnimatorInflater加载xml完成了一个属性动画的操作。
3.3 TypeEvaluator 、 TimeInterpolator这两个类的使用
前面提到TypeEvaluator叫做类型估值器,TimeInterpolator叫做时间插值器,类型估值器用来动态的设置属性变化,而时间插值器用来设置时间相对动画的变化效果。简单的说,TimeInterpolator控制动画的速度,而TypeEvaluator控制动画的值。这两个类的使用比较灵活,可以去参考模拟自然动画的精髓——TimeInterpolator与TypeEvaluator这篇文章,这里举一个模拟抛物线的动画来进行说明。
如果我希望小球抛物线运动【实现抛物线的效果,水平方向100px/s,垂直方向加速度200px/s*s 】,分析一下,貌似只和时间有关系,但是根据时间的变化,横向和纵向的移动速率是不同的,我们该咋实现呢?此时就要重写TypeEvaluator了,因为我们在时间变化的同时,需要返回给对象两个值,x当前位置,y当前位置。
ValueAnimator valueAnimator = new ValueAnimator();
valueAnimator.setDuration(3000);
valueAnimator.setObjectValues(new PointF(0, 0));
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.setEvaluator(new TypeEvaluator()
{
// fraction = t / duration
@Override
public PointF evaluate(float fraction, PointF startValue, PointF endValue)
{
Log.e(TAG, fraction * 3 + "");
// x值为200 * t ,而y值为0.5 * 10 * t * t
PointF point = new PointF();
point.x = 200 * fraction * 3;
point.y = 0.5f * 10 * (fraction * 3) * (fraction * 3);
return point;
}
});
valueAnimator.start();
valueAnimator.addUpdateListener(new AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
PointF point = (PointF) animation.getAnimatedValue();
mBlueBall.setX(point.x);
mBlueBall.setY(point.y);
}
});
从代码可以看出重新定义了类型估值器,设置了x y值得变化,同时将时间插值器设置为默认的线性变化,那么最终小球将以抛物线的动画运动。
本文基本代码都是从其它参考文献拷贝过来,略加修改的,感谢这些作者的辛勤奉献。
1、 Android 属性动画(Property Animation) 完全解析 (上)
2、Android中的View动画和属性动画
3、Android动画之一:Drawable Animation
4、Android 动画学习(一)之View Animation
5、 Android属性动画–基础使用
6、模拟自然动画的精髓——TimeInterpolator与TypeEvaluator
7、Android动画,一篇就够
8、res下的anim和animator文件夹