Android-Preproty animation解析

来源:互联网 发布:商品标题搜索优化 编辑:程序博客网 时间:2024/05/02 02:19

android-Property Animation介绍

属性动画(property animation)系统,是一个健壮的框架,可以实现任何将任何属性设置为动画。不管对象是否被绘制到屏幕上,你都可以声明一个动画去改变它的属性值。属性动画是指在定长时间内改变指定属性的一种动画。

你可以从下面这些特性入手去定义一个属性动画(property animation):

  • Duration(持续时间):你可以指定动画的持续时间,默认值为300ms
  • Time interpolation(时间插值器):你可以指定属性值和动画已执行时间之间的换算方法
  • Repeat count and behavior(动画重复次数和重复的方式):你可以指定动画的重复次数。同时,你也可以指定动画重复的模式,例如是从头到尾从头到尾的效果,还是重头到尾再从尾到头。
  • Animator sets(动画集合):你可以将一系列动画都放入一个动画集合中。之后,通过设置动画集合,以同时或有序或指定掩饰的方式播放那一系列的动画。
  • Frame refresh delay(帧刷新时间):你可以指定播放动画时,刷新屏幕的时间间隔。默认刷新时间是10ms,但是具体有系统决定。

属性动画工作流程


先来看一个简单的例子,图1描述了一个拥有改变x属性的动画的对象,图中x轴坐标系与屏幕表面平行。动画持续40ms,每10ms,屏幕刷新一次,同时对象向x轴坐标方向前进10像素点。在40ms结束之后,动画停止,对象停留在x轴坐标为40的位置。这个例子,其实采用的是一个linear interpolation,抽象类指定属性匀速变化。

这里写图片描述

图1.线性动画实例

介绍了线性动画,接下来让我们来看看非线性动画吧。图2为同样也是描述了一个拥有沿x轴运动动画的对象。不同之处在于,动画不是匀速运动,而是一开始先加速,到快结束时减速的动画。这个动画也是在40ms内运动了40像素点,但不是线性运动。从图中可以看出,动画从起始点到中点进行加速;之后,从中点到结束点进行减速。

非线性动画

图2.非线性动画实例

通过图3,详细介绍属性动画是怎么实现的。

实现原理图

图3.实现原理图

详细介绍:
其中的ValueAnimator是动画的执行类,跟踪了当前动画的执行时间和当前时间下的属性值;ValueAnimator封装了动画的TimeInterpolator和TypeEvaluator。TypeEvaluator用来计算设置动画属性的值。例如图2中,动画采用TimeInterpolator是AccelerateDecelerateInterpolator,然后TypeEvaluator是IntEvaluator。

为了执行一个动画,需要创建一个ValueAnimator对象并指定目标对象的开始值,结束值和持续时间。在调用star()方法后,动画开始。在整个动画过程中,ValueAnimator对象计算动画执行进度百分数,动画进度从0~1。当动画刚刚开始的时候,进度为0,%0;当动画结束时,进度为1,%100。例如图1,当执行了10ms之后,进度为0.25,因为从时间为40ms。

当ValueAnimator算出了动画执行进度之后,ValueAnimator调用当前设置的TimeInterpolator接口对象,去计算interpolator插值(0~1之间)。TimeInterpolator对象通过一定函数将动画执行进度转化为插值分数。例如图2,动画一开始速度比较慢;当动画执行10ms时,动画执行进度为0.25,插值分数为0.15。在比如图1,动画为线性动画,当动画执行10ms时,动画执行进度与插值分数始终相等。

当插值分数计算完成后,ValueAnimator会根据插值分数调用合适的 TypeEvaluator去计算运动中的属性值。例如图2,在动画执行10ms后,动画进度为0.15,动画属性值为:0.15*(40-0),6。

官方例子:
http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/animation/index.html

Property Animation和View Animation不同之处


View Animation只作用于View类及其子类,并且View Animation只作用于视图的位置,大小,旋转,透明度这4方面。View Animation只能改变View被绘制的位置和形式,对View本身属性不做任何改变。

在上面那些方面,Property Animation对View Animation补充。Property Animation可以对任何对执行动画,同时动画属性值真正的发生了变化。

API Overview


**表1**Animator动画执行类

类 描述 ValueAnimator 属性动画执行类,他包含核心功能:计算动画属性值,控制每个动画执行时间,保存动画信息(是否重复执行等),设置动画监听。ValueAimator可以说要一个半自动动画执行类。对于计算动画完成进度,设置动画属性值,更新屏幕帧这类的处理,ValueAnimator是自动完成的。但是对于计算属性值这类的处理,需要我们自己完成。之后,我们会展开实例。 ObjectAnimator 属性动画执行类,ObjectAnimator是ValueAnimator的子类。此类,相当于在ValueAnimator的基础上,进行了封装。你可以快速创建此类动画。 AnimatorSet 动画集合类,可以加入过个动画,设置动画的执行顺序。让集合中的动画按照执行顺序执行。

表2 Evaluators(估值)

类 描述 IntEvaluator Int属性默认使用 FloatEvaluator Float属性默认使用 ArgbEvaluator Color属性默认使用 TypeEvaluator 接口类,用于实现自定义的evaluator。例如,当你创建属性动画,属性值不是int,float和color类型,那么这个时候,你就必须要通过自定义Evaluators来实现了属性动画了。

**表3**Interpolators(插值器)

类/接口 描述 AccelerateDecelerateInterolator 先加速后减速 AccelerateInterpolator 加速 DecelerateInterpolator 减速 AnticipateInterpolator 先向相反方向改变一段再加速播放 AnticipateOvershootInterpolator 先向相反方向改变,再加速播放,会超出目标值然后缓慢移动至目标值,类似于弹簧回弹 BounceInterpolator 快到目标值时值会跳跃 CycleIinterpolator 动画循环一定次数,值的改变为一正弦函数:Math.sin(2 * mCycles * Math.PI * input) LinearInterpolator 线性均匀改变 OvershottInterpolator 最后超出目标值然后缓慢改变到目标值 TimeInterpolator 一个允许自定义Interpolator的接口,以上都实现了该接口

介绍了那么多的概念,我们还是得回归到实践中去。毕竟理论源于实践嘛~

接下来,我们从最简单的ObjectAnimator开始,毕竟ObjectAnimator是系统已经给我们封装好了的类。

ObjectAnimator动画例子


布局文件
后面所有例子,都采用此布局文件

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:padding="0dp"    tools:context="com.example.abe.propertyanimation.MainActivity">    <Button        android:id="@+id/button"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_centerInParent="true"        android:text="Hello World!" /></RelativeLayout>

Activity代码

public class MainActivity extends AppCompatActivity implements View.OnClickListener {    private Button button;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        button = (Button) findViewById(R.id.button);        button.setOnClickListener(this);    }    public void onClick(View v) {//        实现单个属性值改变动画//        ObjectAnimator//                .ofFloat(button, "x", 100F)//                .setDuration(500)//                .start();//        实现多个属性值改变动画        PropertyValuesHolder pvhAlpha = PropertyValuesHolder.ofFloat("alpha", 1f, 0f);        PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x",1f);        PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y",1f);        ObjectAnimator.                ofPropertyValuesHolder(button, pvhAlpha, pvhX, pvhY)                .setDuration(1000)                .start();    }}

在Onclick方法在,实现了多属性动画代码和单属性动画代码。下面是他们的实现效果图

这里写图片描述 这里写图片描述

ObjectAnimator总结

  1. 提供了ofInt、ofFloat、ofObject,这几个方法都是设置动画作用的元素、作用的属性、动画开始、结束、以及中间的任意个属性值。

    当对于属性值,只设置一个的时候,会认为当然对象该属性的值为开始(getPropName反射获取),然后设置的值为终点。如果设置两个,则一个为开始、一个为结束

    动画更新的过程中,会不断调用setPropName更新元素的属性,所有使用ObjectAnimator更新某个属性,必须得有getter(设置一个属性值的时候)和setter方法~

  2. 如果你操作对象的该属性方法里面,比如上例的setRotationX如果内部没有调用view的重绘,则你需要自己按照下面方式手动调用。

    anim.addUpdateListener(new AnimatorUpdateListener()          {              @Override              public void onAnimationUpdate(ValueAnimator animation)              {                view.postInvalidate();                view.invalidate();              }          });  

ValueAnimator动画例子


ValueAnimator动画例子中使用的布局,还是采用ObjectAnimator例子中的布局。

java代码

public class MainActivity extends AppCompatActivity implements View.OnClickListener {    private Button button;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        button = (Button) findViewById(R.id.button);        button.setOnClickListener(this);    }    @Override    public void onClick(View v) {        ValueAnimator animator = new ValueAnimator();        animator.setObjectValues(new PointF(0, 0));        animator.setTarget(button);//        模拟线性插值器        animator.setInterpolator(new TimeInterpolator() {            @Override            public float getInterpolation(float input) {                return input;            }        });//        自定义抛物线        animator.setEvaluator(new TypeEvaluator<PointF>() {            // fraction = t / duration            @Override            public PointF evaluate(float fraction, PointF startValue,                                   PointF endValue) {                PointF point = new PointF();                point.x = 200 * fraction * 3;                point.y = 0.5f * 200 * (fraction * 3) * (fraction * 3);                return point;            }        });//        监听动画更新,同时设给对应属性值        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator animation) {                PointF point = (PointF) animation.getAnimatedValue();                button.setX(point.x);                button.setY(point.y);            }        });        animator.setDuration(1000).start();    }}

效果图

ValueAnimator总结

通过上面的ValueAnimator动画例子,我们实现了自定义ValueAnimator动画的一个完成过程。其实这个动画工作流程,我们在一开始的属性动画工作流程中已经讲过了,下面结合代码深入说明。

实现ValueAnimator动画,总计为4步:

  1. 创建ValueAnimator对象。
  2. 设置Interpolator(插值器),插值器,主要用于计算插值。ValueAnimator调用TimeInterpolator类中的public float getInterpolation(float input)方法,计算interpolator插值(0~1之间)。关于插值的计算方法,我们此方法中自定义实现。

    /* * @param 参数input为ValueAnimator提供的动画完成进度值 * @return 返回值为动画插值 public float getInterpolation(float input){}

    如果我们不自定义Interpolator(插值器),也可以使用系统提供的插值器,插值器在表3中已经列出来了。常用插值器,设置方法

    animator.setInterpolator(new LinearInterpolator());
  3. 设置TypeEvaluator(类型估值),主要用于计算属性值,ValueAnimator会根据插值分数调用evaluator去计算运动中的属性值。在例子中,我们是自定义的方式,来计算运动中的属性值。实现TypeEvaluator自定义,我们需要实现下面方法。

    /*     * @param 参数fraction为刚才Interpolator(插值器)计算出来的插值     * @param 参数startValue为动画开始值(本方法不作使用)     * @param 参数endValue为动画结束值(本方法不作使用)     * @return 计算得到的动画属性值    public PointF evaluate(float fraction, PointF startValue,                               PointF endValue) {            PointF point = new PointF();            point.x = 200 * fraction * 3;            point.y = 0.5f * 200 * (fraction * 3) * (fraction * 3);            return point;    }

    此方法作用,就是通过计算,将之前计算出来的插值变成动画属性值。

    如果满足条件,我们也可以使用系统提供的TypeEvaluator。在表3中已经列出了系统提供的类型估值。常用类型估值,设置方法如下:

    animator.setEvaluator(new IntEvaluator());
  4. 设置属性值。将TypeEvaluator中计算出来的动画属性值赋值给对象。在ObjectAnimator中,系统为我们做好了这一步,但是在ValueAnimator中我们需要自己来完成。下面是完成方法:

    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {        @Override        public void onAnimationUpdate(ValueAnimator animation) {           //我们也可以将属性值,设置给多个对象,或者一个对象的多个值           //设置完全自定义的            PointF point = (PointF) animation.getAnimatedValue();            button.setX(point.x);            button.setY(point.y);        }    });

AnimatorSet动画例子


布局,还是原来的布局~

java代码

public class MainActivity extends AppCompatActivity implements View.OnClickListener {    private Button button;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        button = (Button) findViewById(R.id.button);        button.setOnClickListener(this);    }    @Override    public void onClick(View v) {//        ObjectAnimator anim1 = ObjectAnimator.ofFloat(button, "x", 0f);//        ObjectAnimator anim2 = ObjectAnimator.ofFloat(button, "y", 0f);//        AnimatorSet animSet = new AnimatorSet();//        animSet.setDuration(2000);//        animSet.setInterpolator(new LinearInterpolator());//        //两个动画同时执行//        animSet.playTogether(anim1, anim2);//        animSet.start();        ObjectAnimator anim1 = ObjectAnimator.ofFloat(button, "x", 0f);        ObjectAnimator anim2 = ObjectAnimator.ofFloat(button, "y", 0f);        ObjectAnimator anim3 = ObjectAnimator.ofFloat(button, "alpha",                1f, 0f);        AnimatorSet animSet = new AnimatorSet();        animSet.setDuration(2000);        animSet.setInterpolator(new LinearInterpolator());        //三个动画执行顺序:anim1 -> anim2 -> anim3        animSet.play(anim1).before(anim2);        animSet.play(anim3).after(anim2);        animSet.start();    }}

在此例子中,我们实现了两个动画集合。其中,注释掉部分,两个动画同时执行;而没注释部分,则是按照anim1 -> anim2 -> anim3的顺序执行的。下面是效果图:
这里写图片描述这里写图片描述

AnimatorSet总结
AnimatorSet设置动画执行顺序,常用方法介绍:

表4

方法 描述 Builder before(Animator anim) 动画在anim之后执行 Builder with(Animator anim) 动画和anim同时执行 Builder after(Animator anim) 动画在anim之前执行 void playTogether(Animator… items) items中的所有动画,同时执行

参考


http://developer.android.com/intl/zh-cn/guide/topics/graphics/prop-animation.html#views

0 0
原创粉丝点击