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

Android-Property Animation(属性动画)

2015-12-01 23:47 513 查看
一、Property动画简介:
Property动画系统是一个很强大的框架,几乎可以让任何东西产生动画效果。可以定义一个动画随着时间的推移来改变任何对象的属性,无论它被绘制到屏幕上与否。其主要的Animator有:ValueAnimator、ObjectAnimator和AnimatorSet。
Property动画系统允许定义一个动画的下列属性:
1)Duration:动画持续时间,默认值为300ms。
2)Time interpolation:时间插值,你可以把属性的值如何被计算指定为动画当前逝去时间的函数。
3)Repeat count and behavior:重复次数和行为。你可以指定是否让一个动画重复当它到达持续时间的结束处时,以及重复动画多少次。你还可以指定你是否希望动画反向回放。设置它以向前然后向后地重复反向播放动画,直至到达重复次数。
4)Animator sets:动画集,你可以分组动画进逻辑集合,它们同时地或依次地或在指定延迟后播放。
5)Frame refresh delay:帧刷新延迟,可以指定多久刷新动画的帧,默认是设置每隔10ms刷新,但你的应用程序刷新帧的速度最终依赖于系统整体有多繁忙,以及系统可以多快地提供底层定时器。

二、Property动画如何工作:
这里用一个简单的列子来说明,假如有一个对象在X轴上利用动画使其匀速移动,那么X就相当于此对象的一个property,设定每隔10ms刷新一次,总共移动40ms。那么到移动动画结束时,此对象在此过程中是如何表现的?如图:





当然也可以让此动画过程非匀速移动,就如View动画里面的匀速或者先匀速再加速然后再匀速一样(匀速对应linearInterpolator,后者对应accelerateDecelerateInterpolator):





那么对于上面的列子,属性动画的实现有哪些重要组成部分,下图就很好描述了这点,并展示了主要类如何与另一个类工作的。





ValueAnimator跟踪动画的时间,比如:动画运行了多长时间。ValueAnimator封装了TimeInterpolator,它定义动画的插值(interpolation)和TypeEvaluator,TypeEvaluator定义了如何计算被实现动画的属性的值。这部分可以查看源码:
...
// The time interpolator to be used if none is set on the animation
private static final TimeInterpolator sDefaultInterpolator =
new AccelerateDecelerateInterpolator();
...
private TimeInterpolator mInterpolator = sDefaultInterpolator;
...
/**
* The time interpolator used in calculating the elapsed fraction of this animation. The
* interpolator determines whether the animation runs with linear or non-linear motion,
* such as acceleration and deceleration. The default value is
* {@link android.view.animation.AccelerateDecelerateInterpolator}
*
* @param value the interpolator to be used by this animation. A value of <code>null</code>
* will result in linear interpolation.
*/
@Override
public void setInterpolator(TimeInterpolator value) {
if (value != null) {
mInterpolator = value;
} else {
mInterpolator = new LinearInterpolator();
}
}

三、属性动画和View动画有什么不同:
1)View动画仅支持View对象,而让View对象实现动画的同时并不能让view对象的背景颜色等也发生变换。
2)View动画的另一个缺点是:它只改变视图被绘制的部分,而不是实际的视图本身。举个例子,如果你实现一个动画,让一个Button在屏幕上移动,Button是被正确的绘制,但是你能点击Button的地方却没有变化。为此,你还必须实现自己的逻辑来解决这个问题。
3)对于属性动画,上面提到的那些限制就没有了,可以为属性动画设置任何对象(包括视图和非视图对象)并且对象的任何属性也随着变换。属性动画在其执行动画的方式上也更加强大。在一个较高的水平,指定动画给你想要实现动画的属性,如:颜色、位置和大小,并可以定义动画的各个方面,如插值和多动画同步。
4)属性动画需要较少的时间来建立动画,并且需要更少的代码来实现。如果视图动画完成了你需要做的任何事,或者你现有的代码已经能按照你想要的方式工作,那么就没必要使用属性动画,当然,可以根据不同的条件使用这两种动画。

四、API概要:
1)Animators: ValueAnimator、ObjectAnimator和AnimatorSet。
2)Evaluators:
Class/InterfaceDescription
IntEvaluator计算int属性值的默认evaluator
FloatEvaluator计算float属性值的默认evaluator
ArgbEvaluator计算color属性值的默认evaluator,为16进制。
TypeEvaluator一个接口,允许你创建自己的Evaluator,如果你实现对象动画的属性不是int,float或者color,你必须实现此接口,用来指定如何计算对象属性的动画值,当然,你也可以为int,float和color自定义TypeEvaluator,如果你想进行的不同于这些types的默认行为。
3)Interpolators:可以参考Android-View
Animation(视图动画)。相对于View动画,多了一个TimeInterpolator插值器(一个接口,允许你实现自己的Interpolator)。

五、属性动画实现体验:
1)使用ValueAnimator实现动画:
ValueAnimator提供了3个方法来获得一个ValueAnimator对象:ofInt()、ofFloat()、
ofObject()。以ofFloat为例来实现一个属性动画:

private void startValueAnimation(){
if(mValueAnimator == null){
mValueAnimator = ValueAnimator.ofFloat(0, 500);
}
mValueAnimator.setInterpolator(new AnticipateInterpolator());
mValueAnimator.setTarget(mImageView);
mValueAnimator.setDuration(3000);
mValueAnimator.setRepeatCount(1);
mValueAnimator.start();
mValueAnimator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mImageView.setTranslationX((Float) animation.getAnimatedValue());
mImageView.setTranslationY((Float) animation.getAnimatedValue());
}
});
}




注意:setRepeatCount()方法,设置为1的时候,动画重复是2次,因为默认是0,表示只重复一次。那么设置1的时候就是重复2次,具体逻辑可看源码。

2)使用ObjectAnimator实现动画:


private void startObjectAnimation() {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mImageView, "translate", 0, 500);
objectAnimator.setInterpolator(new AnticipateInterpolator());
objectAnimator.setDuration(3000);
objectAnimator.setRepeatCount(1);
objectAnimator.start();
objectAnimator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mImageView.setTranslationX((Float) animation.getAnimatedValue());
mImageView.setTranslationY((Float) animation.getAnimatedValue());
}
});
}

[/code]


从代码上看实现同样的动画,ObjectAnimator和ValueAnimator相差不大,而事实上ObjectAnimator是继承于ValueAnimator的。

3)使用AnimatorSet:
AnimatorSet大多数情况下都是被用来处理多个动画,比如:要播放一个动画,但是这个动画必须在另外一个动画播放结束后才开始,这个时候就需要AnimatorSet登场了。
举个例子来说明一下:假如要让一个对象移动轨迹呈正方形,就可以先水平向右移动,再垂直向下移动,再水平向左移动,最后垂直向上移动到起始位置,那么这个过程中的先后顺序就可以使用AnimatorSet来控制,如实现代码:

private void startAnimatorSet(){
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(gethValueAnimatorOne()).before(getvValueAnimatorOne());
animatorSet.play(getvValueAnimatorOne()).before(gethValueAnimatorTwo());
animatorSet.play(gethValueAnimatorTwo()).before(getvValueAnimatorTwo());
animatorSet.start();

}

private ValueAnimator gethValueAnimatorOne(){
if(hValueAnimatorOne == null) {
hValueAnimatorOne = ValueAnimator.ofFloat(0, 500);
}
hValueAnimatorOne.setInterpolator(new LinearInterpolator());
hValueAnimatorOne.setTarget(mImageView);
hValueAnimatorOne.setDuration(2000);
hValueAnimatorOne.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mImageView.setTranslationX((Float) animation.getAnimatedValue());
}
});
return hValueAnimatorOne;
}

private ValueAnimator getvValueAnimatorOne(){
if(vValueAnimatorOne == null){
vValueAnimatorOne = ValueAnimator.ofFloat(0, 500);
}
vValueAnimatorOne.setInterpolator(new LinearInterpolator());
vValueAnimatorOne.setTarget(mImageView);
vValueAnimatorOne.setDuration(2000);
vValueAnimatorOne.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mImageView.setTranslationY((Float) animation.getAnimatedValue());
}
});
return vValueAnimatorOne;
}

private ValueAnimator gethValueAnimatorTwo(){
if(hValueAnimatorTwo == null){
hValueAnimatorTwo = ValueAnimator.ofFloat(500, 0);
}
hValueAnimatorTwo.setInterpolator(new LinearInterpolator());
hValueAnimatorTwo.setTarget(mImageView);
hValueAnimatorTwo.setDuration(2000);
hValueAnimatorTwo.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mImageView.setTranslationX((Float) animation.getAnimatedValue());
}
});
return hValueAnimatorTwo;
}

private ValueAnimator getvValueAnimatorTwo(){
if(vValueAnimatorTwo == null){
vValueAnimatorTwo = ValueAnimator.ofFloat(500, 0);
}
vValueAnimatorTwo.setInterpolator(new LinearInterpolator());
vValueAnimatorTwo.setTarget(mImageView);
vValueAnimatorTwo.setDuration(2000);
vValueAnimatorTwo.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mImageView.setTranslationY((Float) animation.getAnimatedValue());
}
});
return vValueAnimatorTwo;
}



效果如图:



当然AnimatorSet不仅可以控制先后,还可以让两个动画同时展现出来,依然使用上面例子,让对象向右移动的时候同时旋转,如实现代码:

private void startAnimatorSet(){
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(gethValueAnimatorOne()).with(getmObjectAnimator());
animatorSet.play(gethValueAnimatorOne()).before(getvValueAnimatorOne());
animatorSet.play(getvValueAnimatorOne()).before(gethValueAnimatorTwo());
animatorSet.play(gethValueAnimatorTwo()).before(getvValueAnimatorTwo());
animatorSet.start();
}
...
private ObjectAnimator getmObjectAnimator(){
if(mObjectAnimator == null){
mObjectAnimator = ObjectAnimator.ofFloat(mImageView, "rotate", 0, 360);
}
mObjectAnimator.setDuration(2000);
mObjectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mImageView.setRotation((Float) animation.getAnimatedValue("rotate"));
}
});
return mObjectAnimator;
}




(图1)

上面配置动画的属性都是在code中配置的,当然也可以使用xml,这个就不再多说了。如:

<setandroid:ordering="sequentially">
<set>
<objectAnimator
android:propertyName="x"
android:duration="500"
android:valueTo="400"
android:valueType="intType"/>
<objectAnimator
android:propertyName="y"
android:duration="500"
android:valueTo="300"
android:valueType="intType"/>
</set>
<objectAnimator
android:propertyName="alpha"
android:duration="500"
android:valueTo="1f"/>
</set>
AnimatorSetset=(AnimatorSet)AnimatorInflater.loadAnimator(myContext,
R.anim.property_animator);
set.setTarget(myObject);
set.start();




六、动画的监听-Animator.AnimatorListener():


回调方法主要有:onAnimationStart、onAnimationEnd、onAnimationCancel、onAnimationRepeat。通过实现这些方法,可以在动画不同的状态下做一些事情。依旧举个例子来测试下。就如上面图1中的效果。上面使用AnimatorSet来实现的,如果不用AnimatorSet是否可以实现?此时就需要这些接口来实现了。在监听到当前动画结束时,在对应的回调中去开始下一个动画。具体代码如下:
private void startAnimatorSet(){
gethValueAnimatorOne().start();
}
private ValueAnimator gethValueAnimatorOne(){
if(hValueAnimatorOne == null) {
hValueAnimatorOne = ValueAnimator.ofFloat(0, 500);
}
hValueAnimatorOne.setInterpolator(new LinearInterpolator());
hValueAnimatorOne.setTarget(mImageView);
hValueAnimatorOne.setDuration(2000);
hValueAnimatorOne.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mImageView.setTranslationX((Float) animation.getAnimatedValue());
}
});
hValueAnimatorOne.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
getmObjectAnimator().start();
}
@Override
public void onAnimationEnd(Animator animation) {
getvValueAnimatorOne().start();
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
return hValueAnimatorOne;
}
private ValueAnimator getvValueAnimatorOne(){
if(vValueAnimatorOne == null){
vValueAnimatorOne = ValueAnimator.ofFloat(0, 500);
}
vValueAnimatorOne.setInterpolator(new LinearInterpolator());
vValueAnimatorOne.setTarget(mImageView);
vValueAnimatorOne.setDuration(2000);
vValueAnimatorOne.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mImageView.setTranslationY((Float) animation.getAnimatedValue());
}
});
vValueAnimatorOne.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
gethValueAnimatorTwo().start();
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
return vValueAnimatorOne;
}
private ValueAnimator gethValueAnimatorTwo(){
if(hValueAnimatorTwo == null){
hValueAnimatorTwo = ValueAnimator.ofFloat(500, 0);
}
hValueAnimatorTwo.setInterpolator(new LinearInterpolator());
hValueAnimatorTwo.setTarget(mImageView);
hValueAnimatorTwo.setDuration(2000);
hValueAnimatorTwo.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mImageView.setTranslationX((Float) animation.getAnimatedValue());
}
});
hValueAnimatorTwo.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
getvValueAnimatorTwo().start();
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
return hValueAnimatorTwo;
}
private ValueAnimator getvValueAnimatorTwo(){
if(vValueAnimatorTwo == null){
vValueAnimatorTwo = ValueAnimator.ofFloat(500, 0);
}
vValueAnimatorTwo.setInterpolator(new LinearInterpolator());
vValueAnimatorTwo.setTarget(mImageView);
vValueAnimatorTwo.setDuration(2000);
vValueAnimatorTwo.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mImageView.setTranslationY((Float) animation.getAnimatedValue());
}
});
return vValueAnimatorTwo;
}
private ObjectAnimator getmObjectAnimator(){
if(mObjectAnimator == null){
mObjectAnimator = ObjectAnimator.ofFloat(mImageView, "rotate", 0, 360);
}
mObjectAnimator.setDuration(2000);
mObjectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mImageView.setRotation((Float) animation.getAnimatedValue("rotate"));
}
});
return mObjectAnimator;
}

最后,这里使用的动画例子比较简单,如果需要更多的练习,可以看看ApiDemo中列子,再结合Genymotion模拟上的ApiDemo看效果。
[/code]

参考:http://developer.android.com/guide/topics/graphics/prop-animation.html
http://developer.android.com/guide/topics/resources/animation-resource.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: