Android-Preproty animation解析

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(估值)

描述
IntEvaluatorInt属性默认使用
FloatEvaluatorFloat属性默认使用
ArgbEvaluatorColor属性默认使用
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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值