[关闭]
@linux1s1s 2017-01-22T08:27:59.000000Z 字数 6119 阅读 2110

Android 动画 Property Animation

AndroidAnimation 2016-06


基本概念

属性动画,这个是在Android 3.0中才引进的,以前学WPF时里面的动画机制好像就是这个,它更改的是对象的实际属性。

对于下图的动画,这个对象的X坐标在40ms内从0移动到40 pixel.按默认的10ms刷新一次,这个对象会移动4次,每次移动40/4=10pixel。

此处输入图片的描述

经插值计算(inteplator)后的插值因子:大约为0.15,上述例子中用了AccelerateDecelerateInterpolator,计算公式为(input即为时间因子):

  1. (Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;

最后根据TypeEvaluator计算出在10ms时的属性值:0.15*(40-0)=6pixel。上例中TypeEvaluator为FloatEvaluator,计算方法为 :

  1. public Float evaluate(float fraction, Number startValue, Number endValue) {
  2. float startFloat = startValue.floatValue();
  3. return startFloat + fraction * (endValue.floatValue() - startFloat);
  4. }

参数分别为上一步的插值因子,开始值与结束值。

ValueAnimator

ValueAnimator包含Property Animation动画的所有核心功能,如动画时间,开始、结束属性值,相应时间属性值计算方法等。应用Property Animation有两个步聚:

1. 计算属性值
2. 根据属性值执行相应的动作,如改变对象的某一属性。

ValuAnimiator只完成了第一步工作,如果要完成第二步,需要实现ValueAnimator.onUpdateListener接口,这个接口只有一个函数onAnimationUpdate(),在这个函数中会传入ValueAnimator对象做为参数,通过这个ValueAnimator对象的getAnimatedValue()函数可以得到当前的属性值如:

  1. ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f);
  2. animation.setDuration(1000);
  3. animation.addUpdateListener(new AnimatorUpdateListener() {
  4. @Override
  5. public void onAnimationUpdate(ValueAnimator animation) {
  6. Log.i("update", ((Float) animation.getAnimatedValue()).toString());
  7. //TODO
  8. /*通过监听这个事件在属性的值更新时执行相应的操作,对于ValueAnimator一般要监听此事件执行相应的动作,不然Animation没意义,在ObjectAnimator(继承自ValueAnimator)中会自动更新属性,如无必要不必监听。在函数中会传递一个ValueAnimator参数,通过此参数的getAnimatedValue()取得当前动画属性值。*/
  9. }
  10. });
  11. animation.setInterpolator(new CycleInterpolator(3));
  12. animation.start();

ObjectAnimator 复合动画三种方式

继承自ValueAnimator,要指定一个对象及该对象的一个属性,当属性值计算完成时自动设置为该对象的相应属性,即完成了Property Animation的全部两步操作。实际应用中一般都会用ObjectAnimator来改变某一对象的某一属性,但用ObjectAnimator有一定的限制,要想使用ObjectAnimator,应该满足以下条件:

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

  1. tv=(TextView)findViewById(R.id.textview1);
  2. btn=(Button)findViewById(R.id.button1);
  3. btn.setOnClickListener(new OnClickListener() {
  4.   @Override
  5.   public void onClick(View v) {
  6.     ObjectAnimator oa=ObjectAnimator.ofFloat(tv, "alpha", 0f, 1f);
  7.     oa.setDuration(3000);
  8.     oa.start();
  9.   }
  10. });

上面加粗部分的说法并不严谨,举个例子如下:

  1. public void rotateyAnimRun(final View view)
  2. {
  3. ObjectAnimator anim = ObjectAnimator.ofFloat(view, "linroid", 1.0F, 0.0F).setDuration(500);
  4. anim.start();
  5. anim.addUpdateListener(new AnimatorUpdateListener()
  6. {
  7. @Override
  8. public void onAnimationUpdate(ValueAnimator animation)
  9. {
  10. float cVal = (Float) animation.getAnimatedValue();
  11. view.setAlpha(cVal);
  12. view.setScaleX(cVal);
  13. view.setScaleY(cVal);
  14. }
  15. });
  16. }

这里linroid就没有相应的set方法,把设置属性的那个字符串,随便写一个该对象没有的属性,就是不管~~咱们只需要它按照时间插值和持续时间计算的那个值,我们自己手动调用~上面的代码就完成了一个复合动画效果。

AnimationSet

除了我们自己在回调方法 onAnimationUpdate 中手动调用完成复合动画效果外,AnimationSet提供了一个把多个动画组合成一个组合的机制,并可设置组中动画的时序关系,如同时播放,顺序播放等。
以下例子同时应用5个动画:

1. 播放anim1;
2. 同时播放anim2,anim3,anim4;
3. 播放anim5。
  1. AnimatorSet bouncer = new AnimatorSet();
  2. bouncer.play(anim1).before(anim2);
  3. bouncer.play(anim2).with(anim3);
  4. bouncer.play(anim2).with(anim4)
  5. bouncer.play(anim5).after(amin2);
  6. animatorSet.start();

除了上面两个方法可以处理复合动画外,还有一个方法也可以处理复合方法:
其实还有更简单的方式,实现一个动画更改多个效果:使用propertyValuesHolder。

  1. public void propertyValuesHolder(View view)
  2. {
  3. PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("alpha", 1f,
  4. 0f, 1f);
  5. PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scaleX", 1f,
  6. 0, 1f);
  7. PropertyValuesHolder pvhZ = PropertyValuesHolder.ofFloat("scaleY", 1f,
  8. 0, 1f);
  9. ObjectAnimator.ofPropertyValuesHolder(view, pvhX, pvhY,pvhZ).setDuration(1000).start();
  10. }

TimeInterplator

Time interplator定义了属性值变化的方式,如线性均匀改变,开始慢然后逐渐快等。在Property Animation中是TimeInterplator,在View Animation中是Interplator,这两个是一样的,在3.0之前只有Interplator,3.0之后实现代码转移至了TimeInterplator。Interplator继承自TimeInterplator,内部没有任何其他代码。

一个接口,允许你自定义interpolator,以上几个都是实现了这个接口

Keyframes

keyFrame是一个 时间/值 对,通过它可以定义一个在特定时间的特定状态,即关键帧,而且在两个keyFrame之间可以定义不同的Interpolator,就好像多个动画的拼接,第一个动画的结束点是第二个动画的开始点。KeyFrame是抽象类,要通过ofInt(),ofFloat(),ofObject()获得适当的KeyFrame,然后通过PropertyValuesHolder.ofKeyframe获得PropertyValuesHolder对象,如以下例子:

  1. Keyframe kf0 = Keyframe.ofInt(0, 400);
  2. Keyframe kf1 = Keyframe.ofInt(0.25f, 200);
  3. Keyframe kf2 = Keyframe.ofInt(0.5f, 400);
  4. Keyframe kf4 = Keyframe.ofInt(0.75f, 100);
  5. Keyframe kf3 = Keyframe.ofInt(1f, 500);
  6. PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("width", kf0, kf1, kf2, kf4, kf3);
  7. ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(btn2, pvhRotation);
  8. rotationAnim.setDuration(2000);

上述代码的意思为:设置btn对象的width属性值使其:

第一个参数为时间百分比,第二个参数是在第一个参数的时间时的属性值。
定义了一些Keyframe后,通过PropertyValuesHolder类的方法ofKeyframe一个PropertyValuesHolder对象,然后通过ObjectAnimator.ofPropertyValuesHolder获得一个Animator对象。
用下面的代码可以实现同样的效果(上述代码时间值是线性,变化均匀):

  1. ObjectAnimator oa=ObjectAnimator.ofInt(btn2, "width", 400,200,400,100,500);
  2. oa.setDuration(2000);
  3. oa.start();

其他参数可以参考

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注