Android中动画的简介
为了使用户的交互更为流畅、自然,动画已经成为一款应用中不可缺少的一部分。Android中动画分类较多,从最早的帧动画、补间动画,到Android3.0之后添加了属性动画,到Android5.0添加了VectorDrawable,使得动画多种多样。
帧动画
帧动画也就是Frame动画。Frame动画是一系列图片按照一定的顺序展示过程,和放电影机制类似。它的原理是在一定时间内切换多张有细微差异的图片从而达到动画效果。
Frame动画可以被定义在xml中,也完全可以编码实现。如果被定义在xml文件中,可以放置在/res下的anim或者drawable目录中,文件名可以作为资源id在代码中引用;如果完全由编码实现,则需要使用到AnimationDrawable对象。。需要注意的是,当我们在xml文件中定义帧动画时,< animation-list>元素必须要作为根元素,它可以包含一个或多个< item>元素。android:onshot如果定义为true的话,此动画只会执行一次,如果为false则一直循环。下面用代码来看一下:
<?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/dingwei"
android:duration="500"></item>
<item
android:drawable="@drawable/chuanyi"
android:duration="500">
</item>
<item
android:drawable="@drawable/huwai"
android:duration="500"></item>
</animation-list>
定义好之后,我们还需要将动画设置给某个View,例如,将该动画设置为某个ImageView背景,代码如下:
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/imageView_anim"
android:background="@drawable/animaion"/>
但是,这个动画并不会在ImageView显示时启动,我们需要通过Java代码启动该动画如下:
ImageView imageView = (ImageView) findViewById(R.id.imageview_anim);
((AnimationDrawable)imageView.getBackground()).start();
补间动画
补间动画也就是tween动画,是操作整个控件让其展现出旋转、渐变、移动、缩放的一种转换过程。同样的,我们可以在xml中定义动画,也可以编码实现。我们按照动画的定义语法完成xml,并放置于/res/anim目录下,文件名可以作为资源id被引用;如果由编码实现,需要用到Animation对象。
下面是一个补间动画集合与补间动画的格式,在该动画执行时,他们将一起执行。
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/linear_interpolator"
android:shareInterpolator="true">
<alpha
android:fromAlpha="0.0"
android:toAlpha="1.0">
</alpha>
<scale
android:fromXScale="1.0"
android:fromYScale="1.0"
android:pivotX="0.5"
android:pivotY="0.5"
android:toXScale="0.5"
android:toYScale="0.5">
</scale>
<translate
android:fromXDelta="0.0"
android:fromYDelta="0.0"
android:toXDelta="50%"
android:toYDelta="50%">
</translate>
<rotate
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="90">
</rotate>
</set>
xml文件必须有一个根元素,可以是alpha,scale,translate,rotate中任意一个,也可以是set来管理一个由前面多个元素组成的动画集合。android:interpolator代表一个插值器资源,可以引用系统自带的插值器资源,也可以自定义,默认是匀速插值器。android:shareInterpolator代表集合里的多个动画是否共享插值器。
补间动画只能运用在View对象之上,并且功能上比较局限。比如旋转动画只能够在x,y轴进行,而不能在z轴进行。补间动画常用于比较简单的动画效果,使用起来也比较简单,我们不多讲了,下面讲一下功能更加强大的属性动画。
属性动画
Android3.0之后,Android推出了新的动画包,也就是属性动画。属性动画不再是针对View设计的,也不限于只能实现,移动,旋转,缩放,淡入、淡出这几种简单的操作,同时也不再只是一种视觉上的动画效果。它实际上是一种在一定时间段内不断修改某个对象的某个属性值的机制。我们只需要告诉系统要操作的属性,动画时长,需要执行哪几种类型的动画,以及动画的初始值和结束值,剩下的工作就可以全部交给系统去完成。
属性动画的核心类——ValueAnimator
ValueAnimator是整个属性动画机制中最核心的一个类,它的作用就是在一定时间内不断地修改某对象的属性值。ValueAnimator的内部使用一种循环的机制来计算值与值之间的动画过渡,我们只需要将属性的取值范围、运行时长提供给ValueAnimator,那么它就会自动帮我们计算属性值在各个动画运行时段的取值,这些值会按照一定的计算方式来实现平滑过渡。除此之外,ValueAnimator还负责管理动画的播放次数,播放模式,以及对动画设置监听器,这使得它成为属性动画中最核心的类型。并且,它的API也设计得非常简单。通常我们都是通过ofFloat、ofInt等静态工厂函数构建ValueAnimator。如下代码:
ValueAnimator.AnimatorUpdateListener mAnimationListener = new ValueAnimator.AnimatorUpdateListener(){
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float newValue = (Float) animation.getAnimatedValue();
Log.d("","新的属性值:"+newValue);
}
};
private void startValueAnimation(){
ValueAnimator animator = ValueAnimator.ofFloat(0.0f,1.0f);
animator.setDuration(1000);
animator.addUpdateListener(mAnimationListener);
animator.start();
}
当然我们也可以在/res/animator目录下的xml文件中定义该动画,实现如下:
<?xml version="1.0" encoding="utf-8"?>
<animator xmlns:android="http://schemas.android.com/apk/res/android"
android:valueFrom="0.0"
android:valueTo="1.0"
android:valueType="floatType" />
然后在Java代码中加载该动画
ValueAnimator animator = (ValueAnimator) AnimatorInflater.loadAnimator(
getApplicationContext(),R.animator.animator
);
animator.start();
对任意属性进行动画操作——ObjectAnimator
ValueAnimator功能强大、自由度高,但是,这也意味着开发人员需要做更多的工作来实现动画需求,这在效率至上的开发人员来说并不是一个很好的选择。所以,实际中我们用的比较多的是ObjectAnimator,因为我们开发中用的最多的就是View的动画,而ObjectAnimator就是可以直接对任意对象的任意属性进行动画操作的类。
ObjectAnimator继承自ValueAnimator,因此,动画实现机制也与ValueAnimator一致。ObjectAnimator最常用的形式也是通过ofFloat,ofInt等静态工厂形式构建Animator对象,如下代码,在1s内将view的alpha属性从1.0过渡到0.3:
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view,"alpha",1.0f,0.3f);
objectAnimator.setDuration(1000);
objectAnimator.start();
ofXXX这样的静态工厂函数通常至少有4个参数。例如,这里的ofFloat函数,参数1是对象,参数2是属性,参数3、4分别是起始值和末位置,当然除了参数1和2,后边的参数可以是0到N。在动画过程中会逐个过渡到各个值。
实现丰富多彩的动画效果——AnimatorSet
独立的动画能够实现的视觉效果毕竟是有限的,要实现一个View在平移过程中同时进行旋转,这种情况下就需要用到AnimationSet将多个动画组合在一起执行。AnimatorSet类提供了一个play()方法,如果我们向这个方法传入一个Animator对象会返回一个AnimatorSet.Builder()的实例。AnimatorSet.Builder中包括以下5个核心方法:
- after(Animator anim)在anim动画执行完之后调用after函数的动画
- after(long delay)将调用after的动画延迟指定毫秒后执行
- before(Animator anim)在anim动画执行完之前再调用before函数的动画
- with(Animator anim)将现有动画和传入的动画同时执行
- playTogether(Animator..anims)将多个动画一起执行
示例如下:
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(anim1).with(anim2).after(anim3).before(anima4);
animatorSet.setDuration(2000);
animatorSet.start();
// animatorSet.playTogether(anim1,anim2,anim3); //将3个动画一起执行
动画执行时间——TypeEvaluator与TimeInterpolator
属性动画的原理就是在一定时间内不断修改某个值。那么在某个事件点这个属性的值是如何确定的呢?
就是通过这个TypeEvaluator计算得到的,中文的翻译就是类型估值器,它的作用是根据当前动画已执行时间占总时间的百分比来计算新的属性值。
在补间动画中我们讲过插值器这个概念,TimeInterpolator就是时间插值器。系统预置的线性插值器有LinearInterpolator,加速插值器AccelerateInterpolator,减速插值器DecelerateInterpolator和加速减速插值器AccelerateDecelerategetInterpolator等。它的作用是获得已执行时间百分比后,通过调用TimeInterpolator的getInterpolation函数来对该百分比做出修改,并且返回。