安卓动画系列之四, 属性动画PropertyAnimation(上)之初步印象

前面讲过补间动画和帧动画,属性动画(PropertyAnimation)是相对前面两种更为高级和灵活的一种动画.属性动画,顾名思义,属性是重要的特点.这里将属性动画的目标看成一个对象,就算不是一个可见的view,甚至只是一个类对象,只要具备必要的属性,也能设置属性动画.


属性动画的基类Animator一般不会直接使用,而是会使用它的子类ValueAnimator 和 ObjectAnimator( ObjectAnimator是ValueAnimator 的子类 ).除了这两个Animator的子类外,属性动画还会接触到AnimatorSet( 可用于创建一个动画集 ),Evaluator( 属性值计算器 ) 和interpolator ( 插值器,设置动画插值属性,比如加速,先加速后减速等等 ). 下面主要讲ValueAnimator和ObjectAnimator如何使用创建动画,和一些主要的方法作用. AnimatorSet 和interpolator 会作为例子在里面使用到,也做简要说明.


ValueAnimator

我们先来看ValueAnimator的源码中,注释是怎么说的.

/**
	 * 当动画运行时,这个类提供了一个简单的时间"引擎",能为运行中的动画计算动画的值并且将这些值设置到目标对象中.
	 * This class provides a simple timing engine for running animations
	 * which calculate animated values and set them on target objects.
	 *
	 * 所有的动画都有唯一的根据时间而计算的属性值(我对timing pulse的意译...)这个timing pulse运行在一个通用的
	 * handler中,从而保证属性每次变化都能在UI线程上得到更新.
	 * <p>There is a single timing pulse that all animations use. It runs in a
	 * custom handler to ensure that property changes happen on the UI thread.</p>
	 *
	 * ValueAnimator是默认使用非线性的时间插值器(先加速后减速).当然也可以通过setInterpolator(TimeInterpolator)
	 * 方法去设置其他不同的插值器,从而改变默认的插值器行为.
	 * 
	 * <p>By default, ValueAnimator uses non-linear time interpolation, via the
	 * {@link AccelerateDecelerateInterpolator} class, which accelerates into and decelerates
	 * out of an animation. This behavior can be changed by calling
	 * {@link ValueAnimator#setInterpolator(TimeInterpolator)}.</p>
	 *
	 * <div class="special reference">
	 * <h3>Developer Guides</h3>
	 * <p>For more information about animating with {@code ValueAnimator}, read the
	 * <a href="{@docRoot}guide/topics/graphics/prop-animation.html#value-animator">Property
	 * Animation</a> developer guide.</p>
	 * </div>
	 */
	@SuppressWarnings("unchecked")
	public class ValueAnimator extends Animator {
		//......
		
	}

注释上面都写了,有些地方翻译不很到位,见谅~ 但总体意思是知道的,ValueAnimator在动画运行的过程中会根据时间去计算一些值(这些值是什么,就看你怎么用,如果动画是针对对象的旋转rotate,那么这些值就是float类型的值). 计算出来的值就会set入对象的属性,从而令对象的属性在整个动画周期中都会变化,最后这些变化如果在UI线程更新,就会变成我们所看到的属性动画. 了解了这个过程,大概我们也就知道为何它的名字叫ValueAnimator了.


下面在代码中去写一下,看看什么效果:

public class TestActivity extends Activity{
	private Button btn_start,btn_cancel;
	private ImageView img_main;
	private ValueAnimator valueAanimator;
	
	
	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.test_main);
		
		btn_start = (Button)findViewById(R.id.btn_start_test);
		btn_cancel = (Button)findViewById(R.id.btn_cancel_test);
		img_main = (ImageView)findViewById(R.id.imv_test_main);
		
		btn_start.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				setAlpha();
			}
		});
		
		btn_cancel.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				if(valueAanimator != null && valueAanimator.isRunning())
					valueAanimator.cancel();
					//end() 和cancel()的区别是,cancel是直接取消动画,end()是停止动画,并且动画停留在最后的画面.
					//valueAanimator.end(); 
			}
		});
	}
	
	/**
	 * 设置透明度
	 */
	private void setValueAnimator()
	{
		valueAanimator = ValueAnimator.ofFloat(0.0f,1.0f);
		//设置动画时间 为3000ms
		valueAanimator.setDuration(3000);
		//设置重复次数为无限次
		valueAanimator.setRepeatCount(ValueAnimator.INFINITE);
		//设置每次动画结束时逆向返回起点重新播放,而ValueAnimator.RESTART是直接重新播放
		valueAanimator.setRepeatMode(ValueAnimator.REVERSE);
		valueAanimator.addUpdateListener(new AnimatorUpdateListener() {
			
			@Override
			public void onAnimationUpdate(ValueAnimator animation) {
				// TODO Auto-generated method stub
				img_main.setAlpha((Float)animation.getAnimatedValue());
			}
		});
		
		valueAanimator.start();
	}
	
	
}


看看是一个图像的alpha从0.0f到1.0f的重复动画:




上面代码中重要的方法已做注释,就不另外说明了.然后在代码的基础上,setValueAnimator()方法中加入大小形变的动画,这里通过AnimatorSet来实现透明度和Scale同时渐变的动画.

private void setValueAnimator()
	{
		valueAanimator = ValueAnimator.ofFloat(0.0f,1.0f);
		//设置动画时间 为3000ms
		valueAanimator.setDuration(3000);
		//设置重复次数为无限次
		valueAanimator.setRepeatCount(ValueAnimator.INFINITE);
		//设置每次动画结束时逆向返回起点重新播放,而ValueAnimator.RESTART是直接重新播放
		valueAanimator.setRepeatMode(ValueAnimator.REVERSE);
		valueAanimator.addUpdateListener(new AnimatorUpdateListener() {
			
			@Override
			public void onAnimationUpdate(ValueAnimator animation) {
				// TODO Auto-generated method stub
				img_main.setAlpha((Float)animation.getAnimatedValue());
			}
		});
		
		valueAnimatorSCA = ValueAnimator.ofFloat(1.0f,3.0f);
		valueAnimatorSCA.setDuration(3000);
		valueAnimatorSCA.setRepeatCount(ValueAnimator.INFINITE);
		valueAnimatorSCA.setRepeatMode(ValueAnimator.REVERSE);
		valueAnimatorSCA.addUpdateListener(new AnimatorUpdateListener() {
			
			@Override
			public void onAnimationUpdate(ValueAnimator animation) {
				// TODO Auto-generated method stub
				img_main.setScaleX((Float)animation.getAnimatedValue());
				img_main.setScaleY((Float)animation.getAnimatedValue());
			}
		});
		
		set = new AnimatorSet();
		//set.playSequentially(items);	//按顺序播放set中所有的动画Animator
		set.playTogether(valueAanimator,valueAnimatorSCA); //同时播放set中所有的动画Animator
		//设置插值器
		set.setInterpolator(new AccelerateDecelerateInterpolator());
		set.start();
	}


同样,这里AnimatorSet的开始和停止取消方法,依旧是start(), cancel(), end(). 

如果要判断Animator的状态, 可以使用isStarted(), isRunning(), isPaused()这些方法来判断属性动画是否已经开始,运行和中止.

下面看看上面代码的图像同时scale X轴和Y轴形变 以及透明度变化的动画效果:



上面还用到一个ValueAnimator.AnimatorUpdateListener的接口,当使用ValueAnimator去计算属性值,就需要加上这个接口去监听并接收计算得到的Animator结果,在接口里面将得到的Animator的属性值set给目标对象.这样才能实现我们所看到效果.后面ObjectAnimator也有类似的接口,后面代码中会提到.


ObjectAnimator

ObjectAnimator作为ValueAnimator的子类,使用的方法也和上面十分类似.但是ObjectAnimator比ValueAnimator更具体,它直接提供属性动画给目标对象,而不需要像ValueAnimator那样先计算属性值,然后将值set给对象.ObjectAnimator已经自动完成了这一步,因此用起来会更轻松一些,也更强大一些.因为只要给出了开始值和结束值,还有属性名,ObjectAnimator就会自动去帮你实现整个效果.


这里依旧上面第一个例子,设置透明度做例子:

private void setValueAnimator()
	{
		//如果value只提供一个值,系统默认这个值是结束值
		valueAanimator = ObjectAnimator.ofFloat(img_main, "alpha", 0.0f,1.0f);
		//设置动画时间 为3000ms
		valueAanimator.setDuration(3000);
		//设置重复次数为无限次
		valueAanimator.setRepeatCount(ValueAnimator.INFINITE);
		//设置每次动画结束时逆向返回起点重新播放,而ValueAnimator.RESTART是直接重新播放
		valueAanimator.setRepeatMode(ValueAnimator.REVERSE);
		
		valueAanimator.setInterpolator(new AccelerateDecelerateInterpolator());
		valueAanimator.start();
	}

设置的时间,插值器方法都一样.而效果和ValueAnimator去实现一样的,



但是从代码可以看出, 在ObjectAnimator的实现中,不再需要像ValueAnimator那样去setAlpha()的设置透明度了,只要填入"alpha",还有起始值和结束值,ObjectAnimator自动实现了属性动画效果.

添加AnimatorListener接口能在动画过程中去实现更多具体的行为.

valueAanimator.addListener(new AnimatorListener() {
			
			@Override
			public void onAnimationStart(Animator animation) {
				// TODO Auto-generated method stub
				//动画开始时回调的方法
			}
			
			@Override
			public void onAnimationRepeat(Animator animation) {
				// TODO Auto-generated method stub
				//动画每次重复时回调的方法
			}
			
			@Override
			public void onAnimationEnd(Animator animation) {
				// TODO Auto-generated method stub
				//动画结束时回调的方法
			}
			
			@Override
			public void onAnimationCancel(Animator animation) {
				// TODO Auto-generated method stub
				//动画停止时回调的方法
			}
		});

当然,上面都是代码去实现属性动画.那么属性动画能不能像Animation一样在xml里面去定义呢?答案是,可以哦.


XML中定义属性动画

首先在res文件夹中新建animator文件夹,然后在里面新建比如 test.xml 的XML资源文件:

<?xml version="1.0"  encoding="utf-8"  ?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:ordering="together"
    >
    <objectAnimator
        android:propertyName="scaleX"
        android:valueFrom="1.0"
        android:valueTo="3.0"
        android:duration="1500"
        android:valueType="floatType"
        android:repeatMode="reverse"
        android:repeatCount="infinite"
        />
    <objectAnimator
        android:propertyName="scaleY"
        android:valueFrom="1.0"
        android:valueTo="3.0"
        android:duration="1500"
        android:valueType="floatType"
        android:repeatMode="reverse"
        android:repeatCount="infinite"
        />

</set>


android:ordering 是set的属性, 值为together 代表里面的所有属性动画同时播放;值为sequentially 则代表依次播放里面的动画.

android:proertyName 是属性名, 比如scaleX, scaleY, alpha等等.

android:valueFrom 是起始值.

android:valueTo 是结束值.

android:duration 是动画时长.

android:valueType 是属性值的类型, 比如float,int等等.

android:repeatCount 是重复次数, 如果是infinite则为无限次.

android:repeatMode 是重复模式,reverse为动画结束后逆向返回起始值重新播放; restart 为动画结束后直接返回起始值播放.


private void setValueAnimator()
	{
		//从XML文件中读取属性动画
		valueAanimator = (AnimatorSet)AnimatorInflater.loadAnimator(TestActivity.this, R.animator.animator);
		//给属性动画设置目标对象
		valueAanimator.setTarget(img_main);
		valueAanimator.start();
		
	}

效果也是一样的,图像同时沿X轴和Y轴形变,也就是大小的变化:



上面对属性动画介绍的文章先写到这里,相信刚接触的童鞋能有初步的认识.看完例子,当自己亲自去实现,应该还会仅仅满足于此. 当然,属性动画还有更高级的一些用法,比如自定义属性计算器Evaluator,自定义属性,利用getter和setter方法,去实现更灵活更强大的效果.甚至自定义插值器,使动画的线性效果达到其他特定的效果等等. 后面会继续探讨.



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值