Android 动画

3.0以前,android支持两种动画模式,tween animation,frame animation,在android3.0中又引入了一个新的动画系统:property animation,这三种动画模式在SDK中被称为property animation,view animation,drawable animation。 

1.View Animation(Tween Animation)

View Animation(Tween Animation):补间动画,给出两个关键帧,通过一些算法将给定属性值在给定的时间内在两个关键帧间渐变。
View animation只能应用于View对象,并只改变View对象绘制的位置,而没有改变View对象本身。它只支持一部分属性,如缩放旋转移动透明度,不会变背景颜色。可以代码定义,也可以用XML定义。可以给一个View同时设置多个动画, 也可以在一个完成之后开始另一个。
用XML定义的动画放在/res/anim/文件夹内,XML文件的根元素可以为<alpha>,<scale>,<translate>,<rotate>,interpolator元素或<set>(表示以上几个动画的集合,set可以嵌套)。
默认情况下,所有动画是同时进行的。
startOffset属性:设置各个动画的开始开始时间来达到动画顺序播放的效果。
定义好动画的XML文件后,可以通过类似下面的代码对指定View应用动画。
ImageView iv = (ImageView)findViewById(R.id.iv);
Animation anim =AnimationUtils.loadAnimation(this, R.anim.anim_scale);
iv.startAnimation(anim);

2.Drawable Animation(Frame Animation)

Drawable Animation(Frame Animation):帧动画,就像GIF图片,通过一系列Drawable依次显示来模拟动画的效果。在XML中的定义方式如下:
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="true">
    <item android:drawable="@drawable/iv1" android:duration="200" />
    <item android:drawable="@drawable/iv2" android:duration="200" />
    <item android:drawable="@drawable/iv3" android:duration="200" />
</animation-list>
 
 示例: 
		protected void onCreate(Bundle savedInstanceState) {
			super.onCreate(savedInstanceState);
	        setContentView(R.layout.main);
	        iv = (ImageView) findViewById(R.id.iv);
	        iv.setBackgroundResource(R.drawable.drawable_anim);
	        anim = (AnimationDrawable) iv.getBackground();
	    }
	    public boolean onTouchEvent(MotionEvent event) {
	        if (event.getAction() == MotionEvent.ACTION_DOWN) {
	            anim.stop();
	            anim.start();
	            return true;
	        }
	        return super.onTouchEvent(event);
	    }


       SDK里讲,AnimationDrawable还没有完全跟Window相关联,如果想要界面显示时就开始动画的话,可以在onWindowFoucsChanged()中调用start()方法。

3.Property Animation

Property Animation只是表示一个值在一段时间内的改变,当值改变时要做什么事情完全是你自己决定的。在Property Animation中,可以对动画应用以下属性:
Duration:动画的持续时间。
TimeInterpolation:属性值的计算方式,如先快后慢。
TypeEvaluator:根据属性的开始、结束值与TimeInterpolation计算出的因子计算出当前时间的属性值。
Repeat Country and behavior:重复次数与方式,如播放3次、5次、无限循环,可以此动画一直重复,或播放完时再反向播放。
Animation sets:动画集合,即可以同时对一个对象应用几个动画,这些动画可以同时播放也可以对不同动画设置不同开始偏移。
Frame refreash delay:多少时间刷新一次,即每隔多少时间计算一次属性值,默认为10ms,最终刷新时间还受系统进程调度与硬件的影响。

3.1Property Animation的工作方式

ValueAnimator即表示一个动画,包含动画的开始值x,结束值x,持续时间t等属性。
ValueAnimator里封装了一个TimeInterpolator,TimeInterpolator定义了属性值在开始值与结束值之间的插值方法。
ValueAnimator里封装了一个TypeAnimator,根据开始、结束值与TimeIniterpolator计算得到的值计算出属性值(pixel)
时间的百分比:input
动画已进行的时间:Math.cos((input+1)*Math.PI)
动画总时间:2.0f
时间因子:Math.cos((input+1)*Math.PI)/2.0f
插值因子:fraction = Math.cos((input+1)*Math.PI)/2.0f +0.5f     (TimeInterpolator时间插值因子)
属性值(pixel)的式求值程序(Type Evaluator)的计算方法是:
public Float evalurate(float fraction, Number startValue, Number endValue){
	float startFloat = startValue.floatValue();
	float endFloat = endValue.floatValue();
	return startFloat + fraction(endFloat - startFloat);
}
参数分别为上一步的差值因子,开始值(pixel)与结束值(pixel)。

3.2 ValueAnimator

ValueAnimator包含Property Animation动画的所有核心功能,如动画时间,开始、结束属性值,相应时间属性值计算方法等。应用Property Animation有两个步聚:
  1. 计算属性值
  2. 根据属性值执行相应的动作,如改变对象的某一属性。
ValuAnimiator只完成了第一步工作,如果要完成第二步,需要实现ValueAnimator.onUpdateListener接口,如:
		 ValueAnimator.ofFloat(0f, 1f);
		 animator.setDuration(1000);
		 animator.addUpdateListener(new AnimatorUpdateListener() {
		     public void onAnimationUpdate(ValueAnimator animation) {
		         Log.i("update", ((Float) animation.getAnimatedValue()).toString());
		         //通过监听这个事件在属性值更新时执行相应操作,对于ValueAnimator一般要监听此事件执行相应的动作。
		     }
		 });
		 animator.setInterpolator(new CycleInterpolator(2));
		 animation.start();
Animator.AnimatorListener
onAnimationStart()
onAnimationEnd()
onAnimationRepeat()
onAnimationCancel
可以继承AnimatorListenerAdapter而不是实现AnimatorListener接口来简化操作,这个类对AnimatorListener中的函数都定义了一个空函数体,这样我们就定义想监听的事件,只定义一空函数体。不用实现每个函数。    
以下是把一个TextView的透明度在1秒内从0变至1。
ObjectAnimator animator = ObjectAnimator.ofFloat(tv, "alpha", 0f, 1f);
animator.setDuration(1000);
animator.addListener(new AnimatorListenerAdapter(){
    public void on AnimationEnd(Animator animation){
        Log.i("Animation","end");
    }
});
oa.start();

3.3 ObjectAnimator

继承自ValueAnimator,要指定一个对象及该对象的一个属性,完成了Property Animation的全部两步操作。实际应用中一般都会用ObjectAnimator来改变某一对象的某一属性,但用ObjectAnimator有一定的限制,要想使用ObjectAnimator,应该满足以下条件:
  • 对象应该有一个setter函数:set<PropertyName>(驼峰命名法)
  • 如上面的例子中,像ofFloat之类的工场方法,第一个参数为对象名,第二个为属性名,后面的参数为可变参数,如果values…参数只设置了一个值的话,那么会假定为目的值,属性值的变化范围为当前值到目的值,为了获得当前值,该对象要有相应属性的getter方法:get<PropertyName>
  • 如果有getter方法,其应返回值类型应与相应的setter方法的参数类型一致。

  如果上述条件不满足,则不能用ObjectAnimator,应用ValueAnimator代替。

3.4 通过AnimationSet应用多个动画

AnimationSet提供了一个把多个动画组合成一个组合的机制,并可设置组中动画的时序关系,如同时播放,顺序播放等。
 以下例子同时应用5个动画:
1、播放anim1
2、同时播放 anim2 anim3 anim4
3、播放anim5
AnimatorSet bouncer = new AnimatorSet();
bouncer.play(anim1).before(anim2);
bouncer.play(anim2).with(anim3);
bouncer.play(anim2).with(anim4)
bouncer.play(anim5).after(amin2);
animatorSet.start();

3.5 TypeEvalutors

根据属性的开始值(pixel)、结束值(pixel)与TimeInterpolation计算出的因子计算出当前时间的属性值,android提供了以下几个evalutor(求值程序):
IntEvaluator:属性的值类型为int;
FloatEvaluator:属性的值类型为float;
ArgbEvaluator:属性的值类型为十六进制颜色值;
TypeEvaluator:一个接口,可以通过实现该接口自定义Evaluator。
自定义TypeEvalutor很简单,只需要实现一个方法,如FloatEvalutor的定义:
		public class FloatEvaluator implements TypeEvaluator {
		    public Object evaluate(float fraction, Object startValue, Object endValue) {
		        float startFloat = ((Number) startValue).floatValue();
		        float endFloat = ((Number)startValue).floatValue();
		        return startFloat + fraction * (endFloat - startFloat);
		    }
		}
根据动画执行的时间跟应用的Interpolator,会计算出一个0~1之间的因子,即evalute函数中的fraction参数。

3.6 TimeInterpolator

time interpolator定义了属性值变化的方式,如线性均匀改变,先慢后渐快等。在Property Animation中是TimeInterpolator,在View Animation中是Interpolator,这两个是一样的,在3.0之前只有Interplator,3.0之后实现代码转移至了TimeInterplator。Interpolator继承自TimeInterpolator,内部没有任何其他代码。
AccelerateInterpolator          加速
DecelerateInterpolator         减速
AccelerateDecelerateInterolator    先加速后减速
AnticipateInterpolator        反向加速
AnticipateOvershootInterpolator    反向加超越,先向相反方向改变,再加速播放超出目的值,后缓慢移动至目的值。
BounceInterpolator         跳跃,快到目的值时值会跳跃,如目的值100,后面的值可能依次为85,77,70,80,90,100
CycleInterpolator          循环,动画循环一定次数,值的改变为一正弦函数:Math.sin(2 * mCycles * Math.PI * input)
LinearInterpolator          线性
OvershottInterpolator        超越,超出目的值的播放速度后缓慢改变到目的值
TimeInterpolator          一个接口,允许你自定义interpolator,以上几个都是实现了这个接口

3.7 当Layout改变时应用动画

ViewGroup中的子元素可以通过setVisibility使其Visible、Invisible或Gone,当有子元素的可见性改变时,可以向其应用动画,通过LayoutTransition类应用此类动画:
transitioner.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, changeDisappearingAnim);

通过setAnimator应用动画,第一个参数表示应用的情境,可以以下4种类型:

  • APPEARING        当一个元素变为Visible时对其应用的动画
  • CHANGE_APPEARING   当一个元素变为Visible时,因系统要重新布局有一些元素,则需要移动的元素应用的动画
  • DISAPPEARING      当一个元素变为InVisible时对其应用的动画
  • CHANGE_DISAPPEARING 当一个元素变为Gone时,因系统要重新布局有一些元素,则需要移动的元素应用的动画 disappearing from the container.

  第二个参数为一Animator。

transitioner.setStagger(LayoutTransition.CHANGE_APPEARING, 10);
此函数设置动画持续时间,参数分别为类型与时间。

3.8 Keyframes

keyFrame是一个 时间/值 对,通过它可以定义一个在特定时间的特定状态,而且在两个keyFrame之间可以定义不同的Interpolator,就相当多个动画的拼接,第一个动画的结束点是第二个动画的开始点。KeyFrame是抽象类,要通过ofInt(),ofFloat(),ofObject()获得适当的KeyFrame,然后通过PropertyValuesHolder.ofKeyframe获得PropertyValuesHolder对象,如以下例子:
		Keyframe kf0 = Keyframe.ofInt(0, 400);
		Keyframe kf1 = Keyframe.ofInt(0.25f, 200);
		Keyframe kf2 = Keyframe.ofInt(0.5f, 400);
		Keyframe kf3 = Keyframe.ofInt(0.75f, 100);
		Keyframe kf4 = Keyframe.ofInt(1f, 500);
		PropertyValuesHolder propertyValues = PropertyValuesHolder.ofKeyframe("width", kf0, kf1, kf2, kf3, kf4);
		ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(btn, pvhRotation);
		objectAnimator.setDuration(2000);
		objectAnimator.start();
上述代码的意思是:设置btn对象的width属性值随时间的变化而变化,先后是400,200,400,100,500。
第一个参数是时间百分比,第二个参数是该时间对应的属性值。
定义了一些Keyframe后,通过PropertyValuesHolder类的方法ofKeyframe封装,然后通过ObjectAnimator.ofPropertyValuesHolder获得Animator。
下面的代码可以实现同样的效果:
ObjectAnimator oa=ObjectAnimator.ofInt(btn2, "width", 400,200,400,100,500);
oa.setDuration(2000);
oa.start();

3.9 Animating Views

在View Animation中,对View应用Animation并没有改变View的属性,动画的实现是通过其Parent View实现的,在View被drawn时Parents View改变它的绘制参数,draw后改变参数无效,这样虽然View的大小或旋转角度等改变了,但view的实际属性没变,所以有效区还是应用动画之前的区域。为了改变这一点,在Android3.0中给View增加了一些参数并对这些参数怎机啊了相应的getter/setter函数(ObjectAnimator要用这些函数改变这些属性):
translationX,translationY:转换坐标(control where the View is Located as a delta from its left androi top coordinates which are set by its layout container.)
rotation,rotationX,rotationY:旋转,rotation用于2D旋转角度,3D中用到后两个。
scaleX,scaleY:缩放
x,y:View的最终坐标
alpha:透明度

跟位置有关的参数有3个,以X坐标为例,可以通过getLeft(),getX(),getTranslateX()获得,若有一个Button按钮,布局时坐标为(30,0):
Button btn = (Button) findViewById(R.id.btn);
btn.getLeft();//30
btn.getX();//30
btn.getTranslationX();//0
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(btn, "translationX", 200);
objectAnimator.setDuration(1000);
objectAnimator.start();
btn.getLeft();//30
btn.getX();//230
btn.getTranslationX();//200
		
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(btn,"x",200);
objectAnimator2.setDuration(1000);
objectAnimator2.start();
btn.getLeft();//30
btn.getX();//200
btn.getTranslationX();//170
无论怎样应用动画,原来的布局时的位置通过getLeft()获得,保持不变;
X是View最终的位置;
对于X动画,源代码是这样的:
case X:
       info.mTranslationX = value - mView.mLeft;
       break;
Property Animation也可以在XML中定义
  • <set> - AnimatorSet
  • <animator> - ValueAnimator
  • <objectAnimator> - ObjectAnimator
XML文件应放大/res/animator/中,通过以下方式应用动画:
AnimatorSet animatorSet = (AnimatorSet) AnimatorInflater.loadAnimator(myContext, R.anim.property_animator);
animatorSet.setTarget(myObject);
animatorSet.start();

3.10 ViewPropertyAnimator

如果需要对一个View的多个属性进行动画可以用ViewPropertyAnimator类,该类对多属性动画进行了优化,会合并一些invalidate()来减少刷新视图,该类在3.1中引入。
以下两段代码实现同样的效果:
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();
myView.animate().x(50f).y(100f);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值