【Android】属性动画

转载请注明出处:http://blog.csdn.net/h28496/44338669


属性动画的原理

通过不断的设置一个View的属性让其出现动画效果。例如,不断地设置一个Button的x值,这个button就会在y轴上运动。

如果学过flash或者其他动画制作的话,应该能理解“补间动画”的意思。属性动画类似于属性上的补间动画。

设置一个View的初始值和结束值,属性动画会随着时间的变化,逐渐地把View的属性从初始值变化到结束值。


实现属性动画的条件

由属性动画的原理可知,要实现在某个方面的动画,首先这个View得有这个属性。即,要有 set属性名() 和 get属性名()方法。

例如:setWidth(), getWidth()。

注意:button自带的getWidth() 和 setWidth()在这里是没有效果的。回想一下在代码中设置一个button的宽度是怎么设置的?

在代码中设置宽度:

button.getLayoutParams().width = 100;
它对应于xml文件中的是
android:layout_width
而不是

android:width
至于width有什么用,我感觉没什么用……看过其他大牛写的博客,也是不太清楚android:width有什么用。


一个简单的例子

效果:点击了Button之后按x轴翻转。Button的布局文件很普通,不贴了。

	public void onClick(View view) {
		ObjectAnimator
		.ofFloat(view, "rotationX", 0f, 360f)
		.setDuration(1000)
		.start();
	}
解释一下:因为Button这个类存在 setRotationX(float p)这个方法,所以第三行的第二个参数 “rotationX” 是有效的。如果写的是一个不存在的参数,或者设置的参数和画面无关,那么画面是没有动画的。

另外,由于setRotationX(float p)的参数类型是float型的,所以第三行用的是 ofFloat(...) 而不是 ofInt(...)或者其他。

setDuration(int p)是动画的时长,单位毫秒。

我在看任玉刚大牛写的博客时他写道,如果没有set属性名()这个方法会导致程序崩溃。但我实测时没有崩溃,只是在logcat报了一条错误,程序继续运行。


如果条件不满足怎么办

如果你想给某个View设置一个动画,但是它没有对应的设置属性的方法怎么办?例如:

我们想给button设置一个宽度逐渐变宽的动画,但是button的setWidth()不能设置显示宽度。

解决的办法:

① 加上set属性()、get属性()方法;(除非是你自定义的控件,否则一般没有权限这么做,下面就不讨论这种情况了)

② 用一个类去包装原始的对象,间接的提供get、set方法;

③ 采用ValueAnimation获得每一个时刻的属性值,然后通过AnimatorUpdateListener监听器根据获得的属性值设置View的状态。

包装原始对象

用这种方式为一个不存在某种方法的类添加方法很常见。考虑到多态,通常包装比继承要好得多。

下面是用MyView包装View的例子:

class MyView{
	View view;
	
	public MyView(View view){
		this.view = view;
	}
	
	public int getWidth(){
		return view.getLayoutParams().width;
	}
	
	public void setWidth(int width){
		this.view.getLayoutParams().width = width;
		this.view.requestLayout();	// 这句话用来重新设置view的位置
	}	
}
有了包装类,我们就来实现一个让Button(它是继承自View的)宽度变宽的动画吧。

效果:在300毫秒内,view的宽度先变成4倍,再恢复到原来的样子。

	public void onClick(View v) {
		MyView view = new MyView(v);// 先包装一下
		int startWidth = v.getWidth();
		ObjectAnimator.ofInt(view, "width", startWidth, startWidth * 4, startWidth)
		.setDuration(300)
		.start();
	}

使用ValueAnimator和AnimatorUpdateListener自己实现

效果:在一秒的时间内,view从y = 0,移动到 y  = 500的地方。

	public void onClick(final View view){
		final ValueAnimator anim = ValueAnimator.ofFloat(0, 500);
		anim.setDuration(1000);
		anim.start();
		
		anim.addUpdateListener(new AnimatorUpdateListener() {
			
			@Override
			public void onAnimationUpdate(ValueAnimator animation) {
				float value = (Float) animation.getAnimatedValue();
				view.setTranslationY(value);
			}
		});
	}

先定义一个值动画(ValueAnimator,中文名个人是意译的)。从名称可以看出,它只是一个“值”的变化,并不涉及到具体的视图。
然后再对这个值动画设置一个监听器。每次值有变化的时候,都将这个值应用到视图的属性上去。例如,值每变化一次,都要重新设置一下位置。

虽然看起来麻烦了一点,但灵活性更高了。


多个动画同时执行

上面的三个例子中,动画都是单独一个。如果我想要在它移动的同时还要改变它的透明度怎么办呢?

和上面的类似,可以利用AnimatorUpdateListener实现;

② 利用PropertyValuesHolder实现;

③ 利用AnimatorSet实现。


利用AnimatorUpdateListener实现

上一个例子中只设置了视图的位置,但实际上可以同时将视图的多个属性设置为那个值。只需多加几个.set属性();

这里为了避免重复,不使用ValueAnimator,而是使用ObjectAnimator。

效果:被点击的视图在1秒内,先变小同时颜色减淡到无,之后再恢复到原状。(建议使用一个ImageView而不是Button,效果更好)

	public void onClick(final View v){
		ObjectAnimator anim = ObjectAnimator.ofFloat(v, "", 1, 0, 1)
				.setDuration(1000);
		anim.start();
		
		anim.addUpdateListener(new AnimatorUpdateListener() {
			
			@Override
			public void onAnimationUpdate(ValueAnimator animation) {
				float currentValue = (Float) animation.getAnimatedValue();
				v.setScaleX(currentValue);
				v.setScaleY(currentValue);
				v.setAlpha(currentValue);
			}
		});		
	}
ObjectAnimator和ValueAnimator一样,也是可以添加监听器的。


利用PropertyValuesHolder实现

这种实现方式代码很简洁,一看便懂。

效果:被点击的视图在1秒内,先变小、颜色减淡到无,之后再恢复到原状,同时整个过程视图旋转了360度。(建议使用一个ImageView而不是Button,效果更好)

	public void onClick(View view){		
		PropertyValuesHolder x = PropertyValuesHolder.ofFloat("scaleX", 1, 0, 1);
		PropertyValuesHolder y = PropertyValuesHolder.ofFloat("scaleY", 1, 0, 1);
		PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 1, 0, 1);
		PropertyValuesHolder rotation = PropertyValuesHolder.ofFloat("rotation", 0, 360);
		
		ObjectAnimator.ofPropertyValuesHolder(view, x, y, alpha, rotation).setDuration(1000).start();
	}

利用AnimatorSet实现

从名字可以看出,这是一个动画的集合。AnimatorSet可以让多个动画同时运行、先后运行

同时运行

效果:被点击的视图在X方向变大的同时,Y方向也变大,之后又同时缩小(建议使用一个ImageView而不是Button,效果更好)

	public void togetherRun(View view){
		// 感觉和PropertyValuesHolder差不多
		ObjectAnimator x = ObjectAnimator.ofFloat(view, "scaleX", 1, 2, 1);
		ObjectAnimator y = ObjectAnimator.ofFloat(view, "scaleY", 1, 2, 1);
		
		AnimatorSet animSet = new  AnimatorSet();
		animSet.setDuration(1000);
		
		animSet.playTogether(x, y);
		animSet.start();		
	}

playTogether(Animator... items)可以让多个动画同时执行。除此之外,还有playWith(Animator item)可以让两个动画同时执行。


先后运行

效果:被点击的视图在X、y方向变大又缩小,之后再平移到右边并返回(建议使用一个ImageView而不是Button,效果更好)

	public void playAfter(View view){
		ObjectAnimator scaleX = ObjectAnimator.ofFloat(ball, "scaleX", 1, 2, 1);
		ObjectAnimator scaleY = ObjectAnimator.ofFloat(ball, "scaleY", 1, 2, 1);
		
		ObjectAnimator x = ObjectAnimator.ofFloat(ball, "x", ball.getX(), ball.getX() + 200, ball.getX());
		
		AnimatorSet animSet = new AnimatorSet();
		// 支持链式编程
		animSet.play(scaleX).with(scaleY);
		animSet.play(x).after(scaleY);
		animSet.setDuration(1000);
		animSet.start();
	}	
}
在先后执行的时候,还可以调用animSet.play(x).after(延迟时间); 使得下一个动画延迟播放。

这里使用的是animSet.play(x).after(scaleY); 即在另一个动画播放完之后再播放,也可以使用

animSet.play(x).before(anim1); 
让一个动画在另一个动画播放前播放。


如何监听动画的结束

animation有三种监听器:

① AnimatorUpdateListener(监听在动画执行过程中的数据或其它情况)

② AnimatorListener(监听动画的‘生命周期’)

③ AnimatorPauseListener(监听动画的暂停与恢复)


有时我们需要在动画结束之后做点事,例如:在点击一个按钮结束后跳转到另一个Activity。

这时我们只需让动画添加一个AnimatorListener监听器。

anim.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
				
			}
		});

如上所示,动画共有四个状态。有时我们并不需要实现所有的方法,只需要其中一个状态就可以了。那我们可以使用AnimatorListenerAdapter,它继承了AnimatorListener接口。空实现了所有方法。

示例:

anim.addListener(new AnimatorListenerAdapter() {
			@Override
			public void onAnimationEnd(Animator animation) {
				view.setY(startY);
			}			
		});


安卓的属性动画大致就讲完了。


参考资料:

http://blog.csdn.net/lmj623565791/article/details/38067475

http://blog.csdn.net/singwhatiwanna/article/details/17841165

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值