Android动画之属性动画

一、属性动画

属性动画是Android提供的一个强大的框架,可以用于任何随时间而变化的对象,不论是否是可以绘制到屏幕上。

特征:

持续时间(Duration):指定动画持续时间,默认300ms;

时间插值:指定根据当前已用时间,属性值的计算方式;

重复计数和行为:指定动画是否要重复以及重复的次数,还可以指定是否反向执行动画;

动画集合:可以组合一组动画,并指定其同时播放,顺序播放或者指定时间间隔播放;

每帧延迟:指定动画每帧刷新时间,默认是10ms。要保持流畅的动画效果,最低要60帧每秒。

二、属性动画工作原理

例子:

Android动画之属性动画_第1张图片

如图,是对“x”属性使用线性插值器,在40ms内从0px变化到40px的例子。每10ms刷新一帧,每次x增加10px。40ms后,动画停止,“x”属性达到40。

Android动画之属性动画_第2张图片

如图所示,描述了主要类之间如何工作。

ValueAnimator对象用于追踪动画的时间,如已经运行的时间,以及动画属性的当前值。ValueAnimator封装了一个TimeInterpolator用于定义动画插值器,和一个TypeEvaluator用于定义属性值的计算方式。如上面的例子就是,TimeInterpolator为LinearInterpolator,TypeEvaluator为IntEvaluator。

定义动画首先创建一个ValueAnimator,并设置要动画的属性的起始和结束值。调用start()启动动画。整个动画期间,ValueAnimator根据动画持续时间以及已经发生的时间来计算elapsed fraction(0-1)。elapsed fraction代表了动画已经完成的时间,0为0%,1为100%。

当ValueAnimator计算出elapsed fraction,其调用TimeInterpolator计算interpolated fraction。interpolated fraction是根据TimeInterpolator将elapsed fraction映射成的一个新fraction。例如上例中,由于使用线性插值器,则interpolated fraction将与elapsed fraction一样。而如果是AccelerateDecelerateInterplator(先加速后减速插值器)当interpolated fraction为0.15时,elapsed fraction为0.25在10ms时(总时间40ms)。

当interpolated fraction计算完,ValueAnimator基于interpolated fraction、起始值、结束值,调用合适的TypeEvaluator来计算要执行动画的属性值。例如使用AccelerateDecelerateInterplator,40ms内从0到40的动画,当到10ms时,interpolated faction是0.15,则属性值为0.15*(40-0) = 6。

三、属性动画与View动画

1.view动画只能用于view,不能用于其他对象。属性动画可以应用于任何对象。

2.view动画只有旋转,缩放等几个动画形式。属性动画可以对对象的任何属性进行。

3.view动画只是改变了view的绘制位置,而不是view本身的位置。例如,view动画把按钮从屏幕左侧移动到右侧,此时点击右侧按钮图形时无法触发点击事件,只有点击其原始的位置,才会触发点击效果。因此需要谨慎处理。而属性动画是对属性的修改。

4.属性动画更加强大。比如可以指定一组动画,比如颜色,位置,尺寸等并为其指定插值或多个动画同步等属性。

5.但是,定义view动画花时间更少,且代码量更少。如果view动画能正确实现你要的效果,就没必要用属性动画。

四、ValueAnimator、ObjectAnimator、AnimatorSet

1.ValueAnimator

属性动画的主要定时引擎,也用于计算属性的值。用于计算动画值的所有核心功能,包含动画的时间细节、重复信息、动画监听器以及设置自定义evaluate类型的功能。执行动画属性有两步:计算动画值以及设置给要执行动画的属性。ValueAnimator不执行第二步,因此必须要监听ValueAnimator中值的更新并且修改要执行动画的对象。

使用:

ValueAnimator animation = ValueAnimator.ofFloat(0f, 100f);
animation.setDuration(1000);
animation.start();
或者

ValueAnimator animation = ValueAnimator.ofObject(new MyTypeEvaluator(), startPropertyValue, endPropertyValue);
animation.setDuration(1000);
animation.start();
添加动画监听器

animation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator updatedAnimation) {
        // 可以使用与动画一样类型的属性动画值
        // 本例中可以使用float值设置translationX属性
        float animatedValue = (float)updatedAnimation.getAnimatedValue();
        textView.setTranslationX(animatedValue);
    }
});

2.ObjectAnimator

ValueAnimator子类,允许设置一个对象及其中的属性来执行动画。当该类计算出动画的新值时,会直接更新属性。一般会更倾向于使用ObjectAnimator,因为在处理动画值以及对象时更容易。但是有时也会用ValueAnimator,因为ObjectAnimator有限制,其要求对象要有属性的访问方法(set、get)。

创建ObjectAnimator与ValueAnimator一样,但要指定属性名:

ObjectAnimator animation = ObjectAnimator.ofFloat(textView, "translationX", 100f);
animation.setDuration(1000);
animation.start();
且有以下要求:

1)该属性必须有set方法,因为ObjectAnimator在动画时会自动更新属性,所以要能访问到该值。如果没有set方法,有三种解决方案:

a)如果有权限,就添加一个set;
b)使用包装类,包装类设置set方法,再由包装类中的set方法来将值发送到原始对象;

c)使用ValueAnimator。

2)如果在ObjectAnimator工厂方法之一中为某参数仅指定一个值,假设他是动画的最终值(没懂)。因此要有get方法。

3)属性的get和set方法的类型必须与指定的起始值和结束值的类型相同。

4)要调用更新方法如invalidate()来强制更新改变的内容。如,调用invalidate()方法强制屏幕重绘等。要在onAnimationUpdate()回调中调用。例如,当改变一个Drawable对象的color时,只有其重绘时才会更新到屏幕上。所有的View中的属性set方法,例如setAlpha()以及setTranslationX()方法都在实现中调用了invalidate()方法,因此不需要为View中的值变化调用invalidate。

3.AnimatorSet

提供运行一组动画的机制。可以设置动画同时运行,顺序运行或者是指定间隔一段时间运行。

AnimatorSet bouncer = new AnimatorSet();
bouncer.play(bounceAnim).before(squashAnim1);
bouncer.play(squashAnim1).with(squashAnim2);
bouncer.play(squashAnim1).with(stretchAnim1);
bouncer.play(squashAnim1).with(stretchAnim2);
bouncer.play(bounceBackAnim).after(stretchAnim2);
ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(bouncer).before(fadeAnim);
animatorSet.start();
上面的播放顺序是:线播放bounceAnim,再同时播放squashAnim1、squashAnim2、stretchAnim1、stretchAnim2,之后播放bounceBackAnim,最后播放fadeAnim。

五、属相动画相关重要类Evaluators、Interpolators、AnimationListener

1.TypeEvaluators

Evaluators让属性动画知道如何计算一个属性的值。它们获取Animator类提供的时间数据,动画的开始与结束值,并据此计算动画值。

有如下几种Evaluators:

IntEvaluator(整形)、FloatEvaluator(浮点型)、ArgbEvaluator(color)。

还可实现TypeEvaluator接口自定义Evaluator,重写evaluate()来指定怎样计算属性动画值。

public class FloatEvaluator implements TypeEvaluator {

    public Object evaluate(float fraction, Object startValue, Object endValue) {
        float startFloat = ((Number) startValue).floatValue();
        return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);
    }
}
其中fraction参数就是interpolator fraction。(先根据经过时间算出elapsed fraction,再根据interpolator算出对应的interpolator fraction)

2.Interpolators

时间插值器,用于指定如何计算每帧动画的属性值的最终参数。系统实现的插值器:

AccelerateDecelerateInterpolator:开始结束慢,中间快;

AccelerateInterpolator:启动慢,然后加速;

AnticipateInterpolator:开始时向后,然后向前甩;

AnticipateOvershootInterpolator:开始向后,然后向前甩,超过之后返回,到达最终值;

BounceInterpolator:动画结束时谈起;

CycleInterPolator:循环播放特定次数;

DecelerateInterpolator:开始快,然后变慢;

LinearInterpolator:匀速改变;

OvershootInterpolator:向前甩一定值后再回到原位。

还可以实现TImeInterpolator来自定义插值器。

插值器会接收一个由动画总时间和动画已经完成时间计算出的elapsed fraction,插值器修改这个fraction以符合动画需要的类型。

AccelerateDecelerateInterpolator:

public float getInterpolation(float input) {
    return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}
LinearInterpolator:

public float getInterpolation(float input) {
    return input;
}

3.动画监听器

1)Animator.AnimatorListener:(具体啥时候调用就不写了,看名字就知道)

onAnimationStart(),onAnimationEnd(),onAnimtionRepeat(),onAnimationCancel(),最后一个也会同时调用onAnimationEnd()。

2)ValueAnimator.AnimatorUpdateListener-onAnimationUpdate()每帧都会调用,在此方法中,使用getAnimatedValue()来获取当前的动画值。注意要更新屏幕的绘制(如果是显示在屏幕上)

也可以使用继承AnimatorListenerAdapter类来替代Animator.AnimatorListener。AnimatorListenerAdapter为AnimatorLister提供了空实现,因此可以实现需要的方法。

ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
fadeAnim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
    balls.remove(((ObjectAnimator)animation).getTarget());
}

六、属性动画使用及其他相关知识

1.指定关键帧(keyFrames)

关键帧对象由时间/值对组成,用于定义在某一特定时刻动画的状态。可以有自己的插值器,用来控制前一关键帧到该关键帧之间的动画行为。

Keyframe kf0 = Keyframe.ofFloat(0f, 0f);
Keyframe kf1 = Keyframe.ofFloat(.5f, 360f);
Keyframe kf2 = Keyframe.ofFloat(1f, 0f);
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2);
ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation)
rotationAnim.setDuration(5000ms);

2.给View添加属性动画

View 的以下属性可以用于属性动画:

traslationX和translationY:用于控制View的位置相对于其父容器设置的坐标的left与top的增量;

rotation,rotationX,rotationY:用于控制旋转中心(2D以及3D);

scaleX和scaleY:控制缩放的中心点;

x 和 y:View的最终位置,x=left+translationX,y=top+translationY;

alpha:视图的透明度,默认是1,不透明。

ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f);

3.ViewPropertyAnimator

ViewPropertyAnimator提供简单的方式并行运行View的部分属性。类似于ObjectAnimator,因为修改了view属性的实际值,但是其同时运行多个动画属性时更加有效。此外,ViewPropertyAnimator实现代码更简洁易于阅读。

多个ObjectAnimator对象

ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();
一个ObjectAnimator

PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();
ViewPropertyAnimator

myView.animate().x(50f).y(100f);

4.在XML中定义动画

需要在res/animator/中创建动画文件。

支持三种标签:ValueAnimator: ;ObjectAnimator: ;AnimationSet:


    
        
        
    
    
inflate该文件为AnimationSer对象,之后设置目标对象,启动。

AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
    R.anim.property_animator);
set.setTarget(myObject);
set.start();
ValueAnimator

代码:

ValueAnimator xmlAnimator = (ValueAnimator) AnimatorInflater.loadAnimator(this,
        R.animator.animator);
xmlAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator updatedAnimation) {
        float animatedValue = (float)updatedAnimation.getAnimatedValue();
        textView.setTranslationX(animatedValue);
    }
});

xmlAnimator.start();

5.属性动画影响UI性能

动画会给UI造成额外的渲染压力(每帧都要刷新)。因此资源密集型的动画会影响UI性能。

为UI创建动画所需的工作被添加到渲染管道的动画阶段。可以通过启动ProfileGPU渲染和监视动画阶段来确定动画是否影响了应用的性能。

6.给ViewGroups添加动画

属性动画提供了对ViewGroup对象执行动画的功能。

可以使用LayoutTrasition类在ViewGroup中给布局改变添加动画。ViewGroup中的视图可以在添加、删除或使用setVisibility()方法时看到出现或者消失的动画。当添加或删除视图时,也可以动画形式进入新位置。调用setAnimator()并传递具有以下LayoutTransition常量的Animator对象在LayoutTransition中定义动画:

APPEARING:出现时展示动画;

CHANGE_APPEARING:出现新的视图时展现动画;

DISAPPEARING:消失时展示动画;

CHANGE_DISAPPEARING:从容器中移除时展示动画。

可以使用自定义的动画,也可以是使用默认的系统动画。

在布局中设置android:animateLayoutChanges='true',可以启用ViewGroup的默认Layouttransition。即LayoutAnimationsByDefault和它对应的layout_animations_by_default.xml布局文件。

还可以使用LayoutAnimationController类自定义过渡动画。

LinearLayout ll = (LinearLayout) findViewById(R.id.ll);
// 设置过渡动画
AlphaAnimation aa = new AlphaAnimation(0, 1);
aa.setDuration(1000);
LayoutAnimationController controller = new LayoutAnimationController(aa, 0.5F);
controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
// 为ViewGroup设置布局动画
ll.setLayoutAnimation(controller);


你可能感兴趣的:(Android,training+guide,随笔)