Android属性动画-Property Animation(三) 使用ValueAnimator完成动画

上一篇文章我们分析了ObjectAnimator的使用方法,这篇文章我们将分析ValueAnimator的使用方法。如果还不会使用ObjectAnimator的朋友可以看一下Android属性动画-Property Animation(二) 使用ObjectAnimator完成动画

Android属性动画-Property Animation(一) 原理分析那篇文章中我们提到过,使用ValueAnimator的话必须要实现ValueAnimator.AnimatorUpdateListener接口,并且要在onAnimationUpdate()方法中手动更新属性值,并且调用invalidate()方法重画。

我们直接看一个例子


public class MainActivity extends Activity {
	private ImageView mBall;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		mBall=(ImageView) findViewById(R.id.my_ball);
		mBall.setOnClickListener(new OnClickListener() {


			@Override
			public void onClick(View v) {
				startAnimation(mBall);
			}
		});


	}

private void startAnimation(final View view) {
		//使用ValueAnimator的静态方法ofFloat(float... values)
		//这个方法的参数是一个可变数组,理论上可以传很多个,第一个是起始位置,最后一个是结束位置
		//也就是evaluate方法里面的(startValue和endValue),一般传一个起始值和一个结束
		//值就够了。起始值是必须要传的!ValueAnimator无法自动获得初始值,不传就会空指针异常,
		//而ObjectAnimator是可以不传起始值的,至于为什么我们下面会分析。
		ValueAnimator anim = ValueAnimator.ofFloat(0.0f,600.0f);
		//设置动画执行时间为3000ms
		anim.setDuration(3000);
		//设置TimeInterpolator为反弹效果
		anim.setInterpolator(new BounceInterpolator());
		//设置TypeEvaluator为FloatEvaluator,这个要与ofFloat一致,
		//我们的起始值和结束值都为float类型,那么计算的时候也要用float计算。
		//如果我们使用ofInt的话,那TypeEvaluator就要用IntEvaluator。
		//这里我们直接用默认的evaluate计算方法了,即result=startValue+fraction*(startValue+endValue)
		anim.setEvaluator(new FloatEvaluator());
		//启动动画
		anim.start();
		//增加一个监听器,用来更新属性
		anim.addUpdateListener(new AnimatorUpdateListener() {
			
			@Override
			public void onAnimationUpdate(ValueAnimator animation) {
				//通过getAnimatedValue()方法获得计算出的实时的值
				float disY=(Float) animation.getAnimatedValue();
				//把这个值赋给小球的y坐标,这样小球就动起来了
				view.setY(disY);
			}
		});
	}
}
有了前面的基础,这个例子已经非常容易理解了。
不知道大家是否还有印象,在第一篇文章中我们说过,Evaluator是用来计算属性值的,它有IntEvaluator、FloatEvaluator、ArgbEvaluator、和 TypeEvaluator,其中前三个都非常好理解,都是计算对应类型数据的属性。而最后一个TypeEvaluator,是由我们自定义类型的,这个类型需要自己实现一个Bean实体类,还是直接看一个例子


首先,我们要创建一个封装了机器人横纵坐标的实体类
public class PointAndrid {
    //机器人的x坐标
	public float x;
	//机器人的y坐标
	public float y;
	public PointAndroid(){}
	public PointAndroid(int x, int y){
		this.x=x;
		this.y=y;
	}
}
接着,是MainActivity
public class MainActivity extends Activity {
	private ImageView mBall;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		mBall=(ImageView) findViewById(R.id.my_ball);
		mBall.setOnClickListener(new OnClickListener() {


			@Override
			public void onClick(View v) {
				startAnimation(mBall);
			}
		});


	}




	private void startAnimation(final View view) {
		//新建一个ValueAnimator实例
		ValueAnimator anim = new ValueAnimator();
		//设置动画执行时间
		anim.setDuration(3000);
		//设置TimeInterpolator,这里设置的是一个反弹效果的interpolator
		anim.setInterpolator(new BounceInterpolator());
		//设置初始值,如果不设置的话会报空指针异常
		anim.setObjectValues(new PointBall(0,0));
		//设置TypeEvaluator,这里我们自定义一个TypeEvaluator,为小球的横纵坐标点
		anim.setEvaluator(new TypeEvaluator
      
      
       
       () {
			/**
			 * 重写这个evaluate方法,这个方法是根据fraction和startValue和endValue
			 * 来计算属性值的,上篇文章中我们是基于默认的evaluate的计算方法
			 * 即result=startValut+fraction*(endValue-startValue)分析的
			 * 现在我们要自定义一个evaluate计算方法,目的是模拟小球的一个抛物线下落的过程,
			 * 没有固定的写法,自己随意创造,如果不清楚fraction怎么来的,请参考第一篇文章。
			 */
			@Override
			public PointBall evaluate(float fraction, PointBall startValue,
					PointBall endValue) {
				
				PointBall point = new PointBall();  
				point.x =  fraction*380;  
				point.y = 60 * (fraction * 3) * (fraction * 3);  
				return point;  
			}
		});
		//调用start()方法,动画就开始执行了
		anim.start();
		//第一篇文章中说过,我们要实现一个监听器,用于更新属性值与重画等操作
		anim.addUpdateListener(new AnimatorUpdateListener() {


			@Override
			public void onAnimationUpdate(ValueAnimator animation) {
				//通过getAnimatedValue()可以得到实时计算出来的小球坐标点的值
				PointAndroid point = (PointAndroid) animation.getAnimatedValue();
				//调用View的setX()和setY()方法,设置小球的横纵坐标,由于setX()和setY()
				//中系统已经写好了重画的操作,我们就不用自己去重画了,否则我们要调用invalidate()方法进行重画
				view.setX(point.x);
				view.setY(point.y);
			}
		});
	}
}
      
      
当然,也可以这样写
private void startAnimation(final View view) {
		ValueAnimator anim = ValueAnimator.ofObject(new TypeEvaluator
       
       
        
        () {

			@Override
			public PointF evaluate(float fraction, PointF startValue,
					PointF endValue) {
				PointF point = new PointF();
				point.x = fraction * 420;
				point.y = 55 * (fraction * 3) * (fraction * 3);
				return point;
			}
		}, new PointF(0,0));
		anim.setDuration(3000);
		anim.setInterpolator(new BounceInterpolator());
		anim.start();
		anim.addUpdateListener(new AnimatorUpdateListener() {
			
			@Override
			public void onAnimationUpdate(ValueAnimator animation) {
				PointF pointF = (PointF) animation.getAnimatedValue();
				view.setX(pointF.x);
				view.setY(pointF.y);
			}
		});
	}
       
       
这两种写法是完全一样的。

注意:我想我还是有必要再强调一下,在ValueAnimator.AnimatorUpdateListener接口中我们重写了onAnimationUpdate()方法,在这个方法中我们修改了属性的值,我们需要调用Invalidate()方法来重画更新过属性值的视图。那为什么我们在上面例子中没有调用invalidate()方法呢,那是因为我们调用的setX()、setScaleY()等函数时,系统已经帮我们写好了invalidate()方法,不用我们自己再去调用了,但如果是我们自己写的setter方法,那一定要记得调用invalidate(),否则视图不会更新的,动画也不会动的!

最后附上一张Interpolators表格,系统自带的这些interpolators已经够我们用得了,基本没有机会让我们自己去写一个。

ValueAnimator我们已经分析完了,下一篇文章我们将分析如何使用AnimatorSet实现动画组合,如何给动画加监听,以及如何使用XML实现属性动画。


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值