Android动画--PropertyAnimation

前面几篇说完view动画和帧动画,这篇来说一下属性动画

首先来说一下属性动画和view动画的对比:

View动画的缺点

1)只有基本的四种变化(旋转、平移、缩放、透明度)

2)经过变化的view在新位置上不能触发点击事件

propertyAnimation是API  11引进来的,如果想在API 11以前的版本使用,需要加入Nineoldandroids库来兼容以前的版本,相比于view动画优点是:

1)只要对象有属性,就能实现其动画效果(要求:该属性得有set和get(可选)方法)

2)在android3.0以后的版本上在view变化后的新位置上点击能触发点击事件

 

当然了propertyAnimation不但可以在xml中定义也可以用java代码来实现

 

在xml文件中,在res/animator下新建xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<!-- ordering有两个值,together是子动画同时播放
					sequentially是按顺序播放 -->
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:ordering="together" >
<!-- animator:对应于ValueAnimator
	 objectAnimator与animator属性都差不多,
	 但objectAnimator多了一个propertyName用来设置对象的属性-->
    <animator
        android:duration="500"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:repeatCount="infinite"
        android:repeatMode="restart"
        android:startOffset="100"
        android:valueFrom="100.0"
        android:valueTo="200.0"
        android:valueType="floatType" >
    </animator>

    <objectAnimator
        android:propertyName="x" >
    </objectAnimator>

</set>

使用上面的xml文件,如下:

Animator animator = AnimatorInflater.loadAnimator(this, R.anim.pre_in);
		animator.setTarget(view);
		animator.start();


使用java代码:

ObjectAnimator:

ObjectAnimator animator = ObjectAnimator.ofFloat(view, "x", 100f, 200f);
		animator.setDuration(500);
		animator.setInterpolator(new AccelerateDecelerateInterpolator());
		animator.setEvaluator(new IntEvaluator());
		animator.start();

ValueAnimator:

ValueAnimator animator = ValueAnimator.ofFloat(100f, 200f);
		animator.setDuration(500);
		animator.setInterpolator(new AccelerateDecelerateInterpolator());
		animator.setEvaluator(new IntEvaluator());
		animator.setTarget(view);
		animator.start();
		animator.addUpdateListener(new AnimatorUpdateListener() {

			@Override
			public void onAnimationUpdate(ValueAnimator animation) {

				view.setX((Float) animation.getAnimatedValue());

			}
		});

valueAnimator比ObjectAnimator多几行代码,但是灵活性比较高

在ValueAnimator中使用了AnimationUpdateListener这个类,用于监听整个动画过程,动画是由许多帧构成的,每播放一帧就会调用onAnimationUpdate()方法,通过这个特点来进行对属性值得改变

 

AnimatorSet:


ValueAnimator animator_01 = ValueAnimator.ofFloat(100f, 200f);
  animator_01.setDuration(500);
  animator_01.setInterpolator(new AccelerateDecelerateInterpolator());
  animator_01.setEvaluator(new IntEvaluator());
  animator_01.setTarget(view);
  animator_01.addUpdateListener(new AnimatorUpdateListener() {   
  @Override
   public void onAnimationUpdate(ValueAnimator animation) {    
   view.setX((Float) animation.getAnimatedValue());   
   }
  });
  ValueAnimator animator_02 = ValueAnimator.ofFloat(100f, 200f);
  animator_02.setDuration(500);
  animator_02.setInterpolator(new AccelerateDecelerateInterpolator());
  animator_02.setEvaluator(new IntEvaluator());
  animator_02.setTarget(view);
  animator_02.addUpdateListener(new AnimatorUpdateListener() { 
  @Override
   public void onAnimationUpdate(ValueAnimator animation) {    
   view.setY((Float) animation.getAnimatedValue());
   }
  });
  AnimatorSet animSet = new AnimatorSet();
  animSet.playTogether(animator_02, animator_01);// animator_02和animator_01同时播放
  //animSet.play(animator_01).after(animator_02); 先animator_01后animator_02
  //animSet.play(animator_01).before(animator_02); 先animator_02后animator_01
  animSet.start();

说完动画,再看看插值器(Interpolator)和估值器(Evaluator):

插值器:根据时间流逝的百分比来计算出当前属性改变的百分比

估值器:根据当前属性改变的百分比来计算出当前属性的值

 

插值器我们可以自己定义,只要实现TimeInterpolator即可:

先来看一下TimeInterpolator源码

package android.animation;

public interface TimeInterpolator {

    /**
     * Maps a value representing the elapsed fraction of an animation to a value that represents
     * the interpolated fraction. This interpolated value is then multiplied by the change in
     * value of an animation to derive the animated value at the current elapsed animation time.
     *
     * @param input A value between 0 and 1.0 indicating our current point
     *        in the animation where 0 represents the start and 1.0 represents
     *        the end
     * @return The interpolation value. This value can be more than 1.0 for
     *         interpolators which overshoot their targets, or less than 0 for
     *         interpolators that undershoot their targets.
     */
    float getInterpolation(float input);
}

就是一个接口,实现该接口即可:

public class MyInterpolator implements Interpolator{

		@Override
		public float getInterpolation(float input) {
			return input;
		}
		
	}


getInterpolationgetInterpolationgetInterpolationgetInterpolation方法中的参数就是时间的百分比,返回值为属性值改变的百分比

 

多个效果组成一个动画除了AnimatorSet外,还可以:

1)通过一个属性值的改变,在onAnimationUpdate中对view进行设置,但是耦合性比较高

ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view, "abc", 0.0f,1.0f);
		
		objectAnimator.addUpdateListener(new AnimatorUpdateListener() {
			
			@Override
			public void onAnimationUpdate(ValueAnimator animation) {
				
				view.setScaleX((Float) animation.getAnimatedValue());
				view.setAlpha((Float) animation.getAnimatedValue());
			}
		});

2)通过PropertyValuesHolder来实现

PropertyValuesHolder holder01 = PropertyValuesHolder.ofFloat("x",50f, 200f); 
		 PropertyValuesHolder holder02 = PropertyValuesHolder.ofFloat("alpha", 0.0f, 1.0f);
		 ValueAnimator valueAnimator = ValueAnimator.ofPropertyValuesHolder(holder01,holder02);
		 valueAnimator.start();

 

 

再来看一下估值器:

package android.animation;

public interface TypeEvaluator<T> {

    public T evaluate(float fraction, T startValue, T endValue);

}


只需实现 TypeEvaluator<T>接口即可:

  public class MyEvaluator implements TypeEvaluator<Float> {  
  /**
   * fraction:属性改变的百分比
   * startValue:开始值
   * endValue:结束值
   */
  @Override
  public Float evaluate(float fraction, Float startValue, Float endValue) {
   float startInt = startValue;
   return (float) (startInt + fraction * (endValue - startValue));
  }
 }

读者可自定义自己的插值器和估值器,来实现千变万化的动画。

 

最后来说一下为什么属性动画中属性要有set和get(可选)方法:注:一下文段来自于任玉刚的《Android开发技术探索》

先来分析一下属性动画的原理:属性动画会根据外界传递的初始值和最终值,以动画的效果多次去调用set方法,每次传递给set方法的值都不一样,确切来说是随着时间的推移,所传递的值越来越接近最终值。总结一下,我们对object的属性abc做动画,如果想让动画生效,要同时满足两个条件:

1)object必须提供setAbc方法,如果动画的时候没有传递初始值。那么还要提供getAbc方法,因为系统要去取abc属性的初始值(如果这条不满足,程序直接Crash)。

2)object的setAbc对属性abc所做的改变必须能够通过某种方法反映出来,比如会带来UI得改变之类的(如果这条不满足,动画不会有效果但不会Crash)。

你可能感兴趣的:(动画,android)