您的位置:首页 > 移动开发 > Android开发

android动画——属性动画(Property Animation)

2016-07-01 13:51 621 查看
视图动画请移步:http://blog.csdn.net/u013424496/article/details/51700077

相对与视图动画 ,属性动画(android3.0提出的) 使用条件:

完全弥补了View anim System的缺陷,你可以为一个对象的任何属性添加动画,(View或者非View),同时对象自己也会被修改。
并且当属性变化的时候,property Anim系统会自动的刷新屏幕。
属性动画系统在处理动画方面也更加强劲。更高级的,你可以指定动画的属性,比如颜色,位置,大小,定义动画的插值器并且同步多个动画。
并且在Property Animation中,改变的是对象的实际属性,如Button的缩放,Button的位置与大小属性值都改变了。而且Property Animation不止可以应用于View,还可以应用于任何对象。

图解类结构



我们就这幅图来说说属性动画吧:

Animator

属性动画主要的类都在android.animation命名空间下,Animator是属性动画的基类,其是一个抽象类,该类定义了许多重要的方法,如下所示:

setDuration(long duration) 

通过setDuration方法可以设置动画总共的持续时间,以毫秒为单位。

start() 

通过start方法可以启动动画,动画启动后不一定会立即运行。如果之前通过调用setStartDelay方法设置了动画延迟时间,那么会在经过延迟时间之后再运行动画;如果没有设置过动画的延迟时间,那么动画在调用了start()方法之后会立即运行。在调用了start()方法之后,动画的isStarted()方法就会返回true;在动画真正运行起来之后,动画的isRunning()方法就会返回true,这时候动画才会调用TimeInterpolator才开始工作计算属性在某个时刻的值。调用动画的start()方法所在的线程必须绑定了一个Looper对象,如果没有绑定就会报错。当然,UI线程(即主线程)早就默认绑定了一个Looper对象,所以在主线程中我们就无需担心这个问题。如果我们想在一个View上使用属性动画,那么我们应该保证我们是在UI线程上调用的动画的start()方法。start()方法运行后会触发动画监听器AnimatorListener的onAnimationStart方法的执行。

setStartDelay(long startDelay) 

可以通过调用setStartDelay方法设置动画的延迟运行时间,比如调用setStartDelay(1000)意味着动画在执行了start()方法1秒之后才真正运行,这种情况下,在调用了start()方法之后,isStarted()方法返回true,表示动画已经启动了,但是在start()方法调用后1s内,isRunning()方法返回false,表示动画还未真正运行,比如在start()方法调用后第0.5秒,由于动画还在延迟阶段,所以isRunning()返回false;在start()方法执行1秒之后,isStarted()方法还是返回true,isRunning()方法也返回了true,表示动画已经真正开始运行了。通过调用getStartDelay()方法可以返回我们设置的动画延迟启动时间,默认值是0。

setInterpolator(TimeInterpolator value) 

我们可以通过调用setInterpolator方法改变动画所使用的时间插值器,由于视图动画也需要使用时间插值器,所以我们可以使用android.view.animation命名空间下的一系列插值器,将其与属性动画一起工作。通过动画的getInterpolator方法可以获取我们设置的时间插值器。

setTarget(Object target) 

可以通过调用动画的setTarget方法设置其要操作的对象,这样可以更新该对象的某个属性值。实际上,该方法对于ValueAnimator作用不大,因为ValueAnimator不是直接与某个对象打交道的。setTarget方法对于ObjectAnimator作用较大,因为ObjectAnimator需要绑定某个要操作的对象,下面会详细介绍。

pause() 

Android中API Level 19在Animator中加入了pause()方法,该方法可以暂停动画的执行。调用pause()方法的线程必须与调用start()方法的线程是同一个线程。如果动画还没有执行start()或者动画已经结束了,那么调用pause()方法没有任何影响,直接被忽略。当执行了pause()方法后,动画的isPaused()方法会返回true。pause()方法运行后会触发动画监听器AnimatorPauseListener的onAnimationPause方法的执行。

resume() 

如果动画通过调用pause()方法暂停了,那么之后可以通过调用resume()方法让动画从上次暂停的地方继续运行。resume()方法也是从API Level 19引入的,并且调用resume()方法的线程必须与调用start()方法的线程是同一个线程。如果动画没有处于暂停状态(即isPaused()返回false),那么调用resume()方法会被忽略。resume()方法运行后会触发动画监听器AnimatorPauseListener的onAnimationResume方法的执行。

end 

end()方法执行后,动画会结束运行,直接从当前状态跳转到最终的完成状态,并将属性值分配成动画的终止值,并触发动画监听器AnimatorListener的onAnimationEnd方法的执行。

cancel() 

cancel()方法执行后,动画也会结束运行,但是与调用end方法不同的是,其不会将属性值分配给动画的终止值。比如一个动画在400ms内将对象的x属性从0渐变为40,当运行到第200ms时调用了cancel()方法,那么属性x的最终值是20,而不是40,这是与调用end()方法不同的,如果在第200ms调用了end()方法,那么属性x的最终值是40。调用cancel()方法后,会先触发AnimatorListener的onAnimationCancel方法的执行,然后触发onAnimationEnd方法的执行。

clone() 

Animator实现了Java.lang.Cloneable接口。Animator的clone()方法会对动画进行拷贝,但是该方法默认实现的只是浅拷贝,子类可以重写该方法以实现深拷贝。

addListener (Animator.AnimatorListener listener) 

可以通过addListener方法向Animator添加动画监听器,该方法接收的是AnimatorListener接口类型的参数,其具有四个方法:onAnimationStart、onAnimationCancel、onAnimationEnd、onAnimationRepeat。我们上面已经介绍了前三个方法,onAnimationRepeat方法会在动画在重复播放的时候被回调。Android中的AnimatorListenerAdapter类是个抽象类,其实现了AnimatorListener接口,并为所有方法提供了一个空实现。

addPauseListener (Animator.AnimatorPauseListener listener) 

可以通过addPauseListener方法可以向Animator添加动画暂停相关的监听器,该方法接收的是AnimatorPauseListener接口类型的参数,具有两个方法:onAnimationPause和onAnimationResume,上面已经提到过,在此不再赘述。AnimatorListenerAdapter同样也实现了AnimatorPauseListener接口,并为所有方法提供了一个空实现。

ValueAnimator

ValueAnimator继承自抽象类Animator。要让属性动画渐变式地更改对象中某个属性的值,可分两步操作:第一步,动画需要计算出某一时刻属性值应该是多少;第二步,需要将计算出的属性值赋值给动画的属性。ValueAnimator只实现了第一步,也就是说ValueAnimator只负责以动画的形式不断计算不同时刻的属性值,但需要我们开发者自己写代码将计算出的值通过对象的setXXX等方法更新对象的属性值。

ValueAnimator中有两个比较重要的属性,一个是TimeInterpolator类型的属性,另一个是TypeEvaluator类型的属性。TimeInterpolator指的就是时间插值器,在上面我们已经介绍过,在此不再赘述。TypeEvaluator是什么呢?TypeEvaluator表示的是ValueAnimator对哪种类型的值进行动画处理。ValueAnimator提供了四个静态方法ofFloat()、ofInt()、ofArgb()和ofObject(),通过这四个方法可以对不同种类型的值进行动画处理,这四个方法对应了四种TypeEvaluator,下面会详细说明。

public static ValueAnimator ofFloat (float… values) 

ofFloat方法接收一系列的float类型的值,其内部使用了FloatEvaluator。通过该方法ValueAnimator可以对float值进行动画渐变,其使用方法如下所示:
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f, 500f);

valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float deltaY = (float)animation.getAnimatedValue();
textView.setTranslationY(deltaY);
}
});

//默认duration是300毫秒
valueAnimator.setDuration(3000);
valueAnimator.start();


其效果如下所示: 



我们通过构造函数指定了动画的起始值为0,终止值为500,动画的默认持续时间是300毫秒,我们通过setDuration()方法设置为3000毫秒。该动画会在3秒内,将值从0到500动画渐变。ValueAnimator提供了一个addUpdateListener方法,可以通过该方法向其添加AnimatorUpdateListener类型的监听器。AnimatorUpdateListener有一个onAnimationUpdate方法,ValueAnimator会每隔一定时间(默认间隔10ms)计算属性的值,每当计算的时候就会回调onAnimationUpdate方法。在该方法中,我们通过调用ValueAnimator的getAnimatedValue()方法获取到当前动画计算出的属性值,然后我们将该值传入textView的setTranslationY()方法中,从而更新了textView的位置,这样就通过ValueAnimator以动画的形式移动textView。

public static ValueAnimator ofInt (int… values) 

ofInt方法与ofFloat方法很类似,只不过ofInt方法接收int类型的值,ofInt方法内部使用了IntEvaluator,其具体使用可参考上面ofFloat的使用代码,在此不再赘述。

public static ValueAnimator ofArgb (int… values) 

从API Level 21开始,ValueAnimator中加入了ofArgb方法,该方法接收一些列代表了颜色的int值,其内部使用了ArgbEvaluator,可以用该方法实现将一个颜色动画渐变到另一个颜色,我们从中可以不断获取中间动画产生的颜色值。你可能纳闷,既然传入的还是int值,那直接用ofInt方法不就行了吗,干嘛还要新增一个ofArgb方法呢?实际上用ofInt方法是不能完成颜色动画渐变的。我们知道一个int值包含四个字节,在Android中第一个字节代表Alpha分量,第二个字节代表Red分量,第三个字节代表Green分量,第四个字节代表Blue分量,且我们常用16进制表示颜色,这样看起来更明显易懂一些,比如int值0xffff0000表示的红色,0xff00ff00表示的是绿色,最前面的ff表示的是Alpha。ofArgb方法会通过ArgbEvaluator将颜色拆分成四个分量,然后分别对各个分量进行动画计算,然后将四个计算完的分量再重新组合成一个表示颜色的int值,这就是ofArgb方法的工作原理。使用方法如下所示:
//ValueAnimator.ofArgb()方法是在API Level 21中才加入的
if(Build.VERSION.SDK_INT >= 21){
//起始颜色为红色
int startColor = 0xffff0000;
//终止颜色为绿色
int endColor = 0xff00ff00;
ValueAnimator valueAnimator = ValueAnimator.ofArgb(startColor, endColor);
valueAnimator.setDuration(3000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int color = (int)animation.getAnimatedValue();
textView.setBackgroundColor(color);
}
});
valueAnimator.start();
}


效果如下所示: 



我们将TextView的颜色通过动画从红色渐变到绿色。

public static ValueAnimator ofObject (TypeEvaluator evaluator, Object… values) 

由于我们要进行动画处理的值是各种各样的,可能不是float、int或颜色值,那我们怎么使用属性动画呢?为此,ValueAnimator提供了一个ofObject方法,该方法接收一个TypeEvaluator类型的参数,我们需要实现该接口TypeEvaluator的evaluate方法,只要我们实现了TypeEvaluator接口,我们就能通过ofObject方法处理任意类型的数据。我们之前提到ofArgb方法是从API Level 21才引入的,如果我们想在之前的这之前的版本中使用ofArgb的功能,怎么办呢?我们可以扩展TypeEvaluator,从而通过ofObject方法实现ofArgb方法的逻辑,如下所示:
//起始颜色为红色
int startColor = 0xffff0000;
//终止颜色为绿色
int endColor = 0xff00ff00;
ValueAnimator valueAnimator = ValueAnimator.ofObject(new TypeEvaluator() {
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
//从初始的int类型的颜色值中解析出Alpha、Red、Green、Blue四个分量
int startInt = (Integer) startValue;
int startA = (startInt >> 24) & 0xff;
int startR = (startInt >> 16) & 0xff;
int startG = (startInt >> 8) & 0xff;
int startB = startInt & 0xff;

//从终止的int类型的颜色值中解析出Alpha、Red、Green、Blue四个分量
int endInt = (Integer) endValue;
int endA = (endInt >> 24) & 0xff;
int endR = (endInt >> 16) & 0xff;
int endG = (endInt >> 8) & 0xff;
int endB = endInt & 0xff;

//分别对Alpha、Red、Green、Blue四个分量进行计算,
//最终合成一个完整的int型的颜色值
return (int)((startA + (int)(fraction * (endA - startA))) << 24) |
(int)((startR + (int)(fraction * (endR - startR))) << 16) |
(int)((startG + (int)(fraction * (endG - startG))) << 8) |
(int)((startB + (int)(fraction * (endB - startB))));
}
}, startColor, endColor);
valueAnimator.setDuration(3000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int color = (int)animation.getAnimatedValue();
textView.setBackgroundColor(color);
}
});
valueAnimator.start();


以上代码实现的效果与ofArgb实现的效果是一样的,都是将TextView从红色渐变到绿色,但是我们可以在API Level 11及以后的版本中都可以使用以上ofObject的代码,通用性更强。效果图:


ObjectAnimator

ObjectAnimator继承自ValueAnimator。我们之前提到,要让属性动画渐变式地更改对象中某个属性的值,可分两步操作:第一步,动画需要计算出某一时刻属性值应该是多少;第二步,需要将计算出的属性值赋值给动画的属性。ValueAnimator只实现了第一步,也就是说ValueAnimator只负责以动画的形式不断计算不同时刻的属性值,但需要我们开发者自己写代码在动画监听器AnimatorUpdateListener的onAnimationUpdate方法中将计算出的值通过对象的setXXX等方法更新对象的属性值。ObjectAnimator比ValueAnimator更进一步,其会自动调用对象的setXXX方法更新对象中的属性值。

ObjectAnimator重载了ofFloat()、ofInt()、ofArgb()和ofObject()等静态方法,我们下面依次说明。

ofFloat(Object target, String propertyName, float… values) 

使用方法如下所示:
float value1 = 0f;
float value2 = 500f;
final ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(textView, "translationY", value1, value2);
objectAnimator.setDuration(3000);
objectAnimator.start();


以上代码实现的效果与通过ValueAnimator的ofFloat方法实现的效果相同,但是可以看出使用ObjectAnimator代码更简洁。在构造函数中,我们将textView作为target传递给ObjectAnimator,然后指定textView要变化的属性是translationY,最后指定渐变范围是从0到500。当动画开始时,ObjectAnimator就会不断调用textView的setTranslationY方法以更新其值。我们此处演示的是ObjectAnimator与View一起工作,其实ObjectAnimator可以与任意的Object对象工作。如果要更新某个对象中名为propery的属性,那么该Object对象必须具有一个setProperty的setter方法可以让ObjectAnimator调用。在ofFloat方法最后如果只填入了一个float值,那么ObjectAnimator需要调用对象的getXXX方法获取对象初始的属性值,然后从该初始的属性值渐变到终止值。

ofInt(Object target, String propertyName, int… values) 

参见ofFloat的使用方法。

ofArgb(Object target, String propertyName, int… values) 

使用代码如下所示:
//ObjectAnimator.ofArgb()方法是在API Level 21中才加入的
if(Build.VERSION.SDK_INT >= 21){
int startColor = 0xffff0000;
int endColor = 0xff00ff00;
ObjectAnimator objectAnimator = ObjectAnimator.ofArgb(textView, "backgroundColor", startColor, endColor);
objectAnimator.setDuration(3000);
objectAnimator.start();
}


效果图参见ValueAnimator中对应的图片。

ofObject(Object target, String propertyName, TypeEvaluator evaluator, Object… values) 

使用代码如下所示:
int startColor = 0xffff0000;
int endColor = 0xff00ff00;
ObjectAnimator objectAnimator = ObjectAnimator.ofObject(textView, "backgroundColor", new TypeEvaluator() {
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
int startInt = (Integer) startValue;
int startA = (startInt >> 24) & 0xff;
int startR = (startInt >> 16) & 0xff;
int startG = (startInt >> 8) & 0xff;
int startB = startInt & 0xff;

int endInt = (Integer) endValue;
int endA = (endInt >> 24) & 0xff;
int endR = (endInt >> 16) & 0xff;
int endG = (endInt >> 8) & 0xff;
int endB = endInt & 0xff;

return (int)((startA + (int)(fraction * (endA - startA))) << 24) |
(int)((startR + (int)(fraction * (endR - startR))) << 16) |
(int)((startG + (int)(fraction * (endG - startG))) << 8) |
(int)((startB + (int)(fraction * (endB - startB))));
}
}, startColor, endColor);
objectAnimator.setDuration(3000);
objectAnimator.start();


效果图参见ValueAnimator中对应的图片。

AnimatorSet

AnimatorSet继承自Animator。AnimatorSet表示的是动画的集合,我们可以通过AnimatorSet把多个动画集合在一起,让其串行或并行执行,从而创造出复杂的动画效果。

我们想让TextView先进行旋转,然后进行平移,最后进行伸缩,我们可以通过AnimatorSet实现该效果,代码如下所示:
```
//anim1实现TextView的旋转动画
Animator anim1 = ObjectAnimator.ofFloat(textView, "rotation", 0f, 360f);
anim1.setDuration(2000);
//anim2和anim3TextView的平移动画
Animator anim2 = ObjectAnimator.ofFloat(textView, "translationX", 0f, 300f);
anim2.setDuration(3000);
Animator anim3 = ObjectAnimator.ofFloat(textView, "translationY", 0f, 400f);
anim3.setDuration(3000);
//anim4实现TextView的伸缩动画
Animator anim4 = ObjectAnimator.ofFloat(textView, "scaleX", 1f, 0.5f);
anim4.setDuration(2000);

//第一种方式
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playSequentially(anim1, anim2, anim4);
animatorSet.playTogether(anim2, anim3);
animatorSet.start();

//第二种方式
/*AnimatorSet anim23 = new AnimatorSet();
anim23.playTogether(anim2, anim3);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playSequentially(anim1, anim23, anim4);
animatorSet.start();*/

//第三种方式
/*AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(anim1).before(anim2);
animatorSet.play(anim2).with(anim3);
animatorSet.play(anim4).after(anim2);
animatorSet.start();*/
```


效果如下所示: 



动画anim1用于旋转TextView,anim2用于在X轴方向偏移TextView,anim3用于在Y轴方向偏移TextView,anim4用于缩放TextView。我们在以上代码中提供了三种方式通过AnimationSet把这四个动画组合到一起,第二种方式和第三种方式被注释起来了。

其实有很多种办法实现上述效果,这里只介绍一下上述三种方式的思路。

在第一种方式中,调用了animatorSet.playSequentially(anim1, anim2, anim4),该方法将anim1、anim2以及anim4按顺序串联起来放到了animatorSet中,这样首先会让动画anim1执行,anim1执行完成后,会依次执行动画anim2,执行完anim2之后会执行动画anim3。通过调用animatorSet.playTogether(anim2, anim3),保证了anim2和anim3同时执行,即动画anim1完成之后会同时运行anim2和anim3。

在第二种方式中,我们首先创建了一个AnimatorSet变量anim23,然后通过anim23.playTogether(anim2, anim3)将anim2和anim3组合成一个小的动画集合。然后我们再把anim1、anim23以及anim4一起传入到animatorSet.playSequentially(anim1, anim23, anim4)中,这样anim1、anim23、anim4会依次执行,而anim23中的anim2和anim3会同时执行。该方式同时也演示了可以将一个AnimatorSet作为动画的一部分放入另一个AnimatorSet中。

在第三种方式中,我们使用了AnimatorSet的play方法,该方法返回AnimatorSet.Builder类型,animatorSet.play(anim1).before(anim2)确保了anim1执行完了之后执行anim2,animatorSet.play(anim2).with(anim3)确保了anim2和anim3同时执行,animatorSet.play(anim4).after(anim2)确保了anim2执行完了之后执行anim4。需要说明的是animatorSet.play(anim1).before(anim2)与animatorSet.play(anim2).after(anim1)是完全等价的,之所以在上面代码中有的写before,有的写after,只是为了让大家多了解一下API。

结尾总结下:Translate,Alpha,Scale,Rotate这几种动画的一些属性


Translate

对应的属性名为TranslateX和TranslateY

TranslateX:参考轴为Y轴

如果value < 0 则位于Y轴的左侧。

如果value > 0 则位于Y轴的右侧。

TranslateY:参考轴为X轴

如果value < 0 则位于X轴的下方。

如果value > 0 则位于X轴的上方。


Scale

对应的属性名为 ScaleX、ScaleY

android:pivotX

android:pivotY

value 为缩放比例


Rotate:对于的属性名为rotation

android:pivotX 旋转中心X坐标

android:pivotY 旋转中心Y坐标

rotation: value 为旋转角度

value > 0 在参考位置的顺时针方向

value < 0 在参考位置的逆时针方向

如果不设置privotX和privotY,默认是Target的中心为缩放坐标

ObjectAnimator.ofFloat(target, “rotation”, -90, 0),

ObjectAnimator.ofFloat(target, “pivotX”, x, x),

ObjectAnimator.ofFloat(target, “pivotY”, y, y)

这里从逆时针方向90度以X和Y为中心坐标,旋转到目标位置

为了整个过程的时序上保持一致。所以这里privotX和privotY与rotation的参数都为2,旋转中心始终不变


Alpha

0.0表示完全透明,1.0表示完全不透明,Float值。

这个动画比较简单,只是使用的时候,参数值的设置,可以达到不同的效果。

比如Bling Bling的效果:

ObjectAnimator.ofFloat(target,”alpha”,1,0,1,0,1)

参考文档:http://blog.csdn.net/iispring/article/details/50322625

http://www.lightskystreet.com/2014/12/04/propertyview-anim-analysis/

Translate,Alpha,Scale,Rotate这几种动画的一些属性更多介绍
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  属性动画