Android动画之帧动画,补间动画和属性动画

Android动画基本上可以分为视图动画和属性动画,视图动画包括帧动画和补间动画。

一.概述

通过本篇文章的学习,你将学会:
1.如何使用帧动画
2.如何使用补间动画
3.如何使用属性动画

二.帧动画

帧动画就是按照顺序播放一帧一帧的照片达到动画的效果。我们可以看一下实现过程:
在drawable目录下新建frame_list.xml:

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">
    <item
        android:drawable="@mipmap/a_0"
        android:duration="100" />
    <item
        android:drawable="@mipmap/a_1"
        android:duration="100" />
    <item
        android:drawable="@mipmap/a_2"
        android:duration="100" />
</animation-list>
<!--oneshot表示是否只播放一次,默认false-->

在activity用两个按钮来启动动画和暂停动画:

    Button bt_start, bt_stop;
    ImageView iv;
    AnimationDrawable animationDrawable;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_frame);
        bt_start = (Button) findViewById(R.id.bt_start);
        bt_stop = (Button) findViewById(R.id.bt_stop);
        iv = (ImageView) findViewById(R.id.iv);
        iv.setImageResource(R.drawable.frame_list);
        animationDrawable = (AnimationDrawable) iv.getDrawable();
        bt_start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //启动帧动画
                animationDrawable.start();
            }
        });
        bt_stop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //暂停帧动画
                animationDrawable.stop();
            }
        });
    }

帧动画使用简单方便,但是注意在比较复杂的时候图片比较多的时候容易发生oom,因此尽量避免使用尺寸较大的图片。

三.补间动画

补间动画是通过确定视图开始和结束的样式,然后中间的样式由系统进行补全形成。但是它只是去改变了视觉效果,并不会改变控件本身的属性。补间动画包括基本的平移动画,缩放动画,旋转动画和透明度动画,我们也可以将这些基本动画进行组合在一起。
所有的补间动画共有的属性:
duration:动画时长
startOffset:动画延迟开始时间
fillAfter:动画结束后是否停留在结束状态
repeatMode:重复播放动画模式restart代表正序重放,reverse代表倒序回放
repeatCount:重放次数(+1),为infinite时无限重复
interpolator:插值器:选择动画变化的模式,有匀速,加速,减速,先加速在减速。。。
平移动画
平移动画有其特有的属性,平移动画在水平方向初始值和结束值,在竖直方向的初始值和结束值
有两种方式实现平移动画:

  • xml形式:
    1.在res目录下新建anim文件夹,创建animation_translate.xml:
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="3000"
    android:startOffset ="1000"
    android:fillAfter = "false"
    android:repeatMode= "reverse"
    android:repeatCount = "infinite"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"

    android:fromXDelta="0"
    android:toXDelta="500"
    android:fromYDelta="0"
    android:toYDelta="0">

    <!--duration:动画时长
    startOffset:动画延迟开始时间
    fillAfter:动画结束后是否停留在结束状态
    repeatMode:重复播放动画模式restart代表正序重放,reverse代表倒序回放
    repeatCount:重放次数(+1),为infinite时无限重复
    interpolator:插值器:选择动画变化的模式,有匀速,加速,减速,先加速在减速。。。

    以上是所有补间动画共有的属性,以下是平移动画特有的属性
    fromXDelta:平移动画在水平方向x初始值
    toXDelta:平移动画在水平方向x结束值
    fromYDelta:平移动画在竖直方向y初始值
    toYDelta:平移动画在竖直方向y结束值-->
</translate>

各个参数的意义在xml文件中已注明
2.通过AnimationUtils.loadAnimation方法获取Animation对象让控件开始动画:

        Animation animation = AnimationUtils.loadAnimation(this, R.anim.animation_translate);
        bt_translate.startAnimation(animation);
  • java动态执行动画:
        //分别对应xml中的fromXDelta,toXDelta,fromYDelta,toYDelta
        Animation animation2 = new TranslateAnimation(0, 500, 0, 500);
        animation2.setStartOffset(1000);//动画延迟开始时间
        animation2.setDuration(3000);//动画持续时长
        bt_translate2.startAnimation(animation2);

注意:两种方式都一定需要有duration属性设置动画时长,否则动画不起作用
缩放动画
缩放动画有其特有的属性,缩放动画在水平方向起始缩放倍数和结束缩放倍数,在竖直方向的初始缩放倍数和结束缩放倍数
有两种方式实现缩放动画:

  • xml形式:
    1.在res的anim目录下创建animation_scale.xml:
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="3000"
    android:startOffset ="1000"
    android:fillAfter = "false"
    android:repeatMode= "reverse"
    android:repeatCount = "infinite"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"

    android:fromXScale="0"
    android:toXScale="2"
    android:fromYScale="1"
    android:toYScale="1"
    android:pivotX="50%"
    android:pivotY="50%">

    <!--fromXScale:动画在水平方向X的起始缩放倍数
    fromYScale:动画在竖直方向Y的起始缩放倍数
    pivotX:缩放轴点的x坐标
    pivotY:缩放轴点的y坐标

    pivotX pivotY,可取值为数字,百分比,或者百分比p
    设置为数字时(如50),轴点为View的左上角的原点在x方向和y方向加上50px的点。在Java代码里面设置这个参数的对应参数是Animation.ABSOLUTE。
    设置为百分比时(如50%),轴点为View的左上角的原点在x方向加上自身宽度50%和y方向自身高度50%的点。在Java代码里面设置这个参数的对应参数是Animation.RELATIVE_TO_SELF。
    设置为百分比p时(如50%p),轴点为View的左上角的原点在x方向加上父控件宽度50%和y方向父控件高度50%的点。在Java代码里面设置这个参数的对应参数是Animation.RELATIVE_TO_PARENT-->
</scale>

各个参数的意义在xml文件中已注明
2.通过AnimationUtils.loadAnimation方法获取Animation对象让控件开始动画:

        Animation animation = AnimationUtils.loadAnimation(this, R.anim.animation_scale);
        bt_scale1.startAnimation(animation);
  • java动态执行动画:
        //参数分别对应fromXScale,toXScale,fromYScale,toYScale,缩放轴点X坐标类型,pivotX,缩放轴点Y坐标类型,pivotY
        Animation animation2 = new ScaleAnimation(0, 2, 0, 2, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        animation2.setStartOffset(1000);
        animation2.setDuration(3000);
        bt_scale2.startAnimation(animation2);

注意:两种方式都一定需要有duration属性设置动画时长,否则动画不起作用
旋转动画
旋转动画有其特有的属性,旋转动画在动画开始时视图的旋转角度,在动画结束时视图的旋转角度
有两种方式实现缩放动画:

  • xml形式:
    1.在res的anim目录下创建animation_rotate.xml:
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="3000"
    android:startOffset ="1000"
    android:fillAfter = "false"
    android:repeatMode= "reverse"
    android:repeatCount = "infinite"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"

    android:fromDegrees="0"
    android:toDegrees="360"
    android:pivotX="50%"
    android:pivotY="50%">

    <!--fromDegrees:动画开始时 视图的旋转角度    正数 = 顺时针,负数 = 逆时针
    toDegrees:动画结束时 视图的旋转角度
    pivotX:旋转轴点的x坐标
    pivotY:旋转轴点的y坐标

    pivotX pivotY,可取值为数字,百分比,或者百分比p
    设置为数字时(如50),轴点为View的左上角的原点在x方向和y方向加上50px的点。在Java代码里面设置这个参数的对应参数是Animation.ABSOLUTE。
    设置为百分比时(如50%),轴点为View的左上角的原点在x方向加上自身宽度50%和y方向自身高度50%的点。在Java代码里面设置这个参数的对应参数是Animation.RELATIVE_TO_SELF。
    设置为百分比p时(如50%p),轴点为View的左上角的原点在x方向加上父控件宽度50%和y方向父控件高度50%的点。在Java代码里面设置这个参数的对应参数是Animation.RELATIVE_TO_PARENT-->
</rotate>

各个参数的意义在xml文件中已注明
2.通过AnimationUtils.loadAnimation方法获取Animation对象让控件开始动画:

        Animation animation = AnimationUtils.loadAnimation(this, R.anim.animation_rotate);
        bt_rotate1.startAnimation(animation);
  • java动态执行动画:
        //参数分别对应fromDegrees,toDegrees,旋转轴点X坐标类型,pivotX,旋转轴点Y坐标类型,pivotY
        Animation animation2 = new RotateAnimation(0, -360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        animation2.setStartOffset(1000);
        animation2.setDuration(3000);
        bt_rotate2.startAnimation(animation2);

注意:两种方式都一定需要有duration属性设置动画时长,否则动画不起作用
透明度动画
透明度动画有其特有的属性,透明度动画在动画开始时视图的初始透明度,在动画结束时视图的结束透明度
有两种方式实现透明度动画:

  • xml形式:
    1.在res的anim目录下创建animation_alpha.xml:
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="3000"
    android:startOffset ="1000"
    android:fillAfter = "false"
    android:repeatMode= "reverse"
    android:repeatCount = "infinite"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"

    android:fromAlpha="0"
    android:toAlpha="1">

    <!--fromAlpha:动画开始时视图的初始透明度
    toAlpha:动画结束时视图的结束透明度-->
</alpha>

各个参数的意义在xml文件中已注明
2.通过AnimationUtils.loadAnimation方法获取Animation对象让控件开始动画:

        Animation animation = AnimationUtils.loadAnimation(this, R.anim.animation_alpha);
        bt_alpha1.startAnimation(animation);
  • java动态执行动画:
        //参数分别对应fromAlpha,toAlpha
        Animation animation2 = new AlphaAnimation(0, 1);
        animation2.setStartOffset(1000);
        animation2.setDuration(3000);
        bt_alpha2.startAnimation(animation2);

注意:两种方式都一定需要有duration属性设置动画时长,否则动画不起作用
组合动画
组合动画就是将上面的四种动画组合在一起,同事拥有平移,缩放,旋转和透明度变化的动画。同样有两种方式:

  • xml形式:
    1.在res目录下新建anim文件夹,创建animation_set.xml:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <alpha
        android:duration="1000"
        android:fromAlpha="0"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:toAlpha="1" />
    <translate
        android:duration="2000"
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:startOffset="3000"
        android:toXDelta="500"
        android:toYDelta="0" />
    <rotate
        android:duration="3000"
        android:fromDegrees="0"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:pivotX="50%"
        android:pivotY="50%"
        android:repeatCount="infinite"
        android:repeatMode="restart"
        android:toDegrees="360" />
    <scale
        android:duration="3000"
        android:fromXScale="1"
        android:fromYScale="1"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:pivotX="50%"
        android:pivotY="50%"
        android:startOffset="4000"
        android:toXScale="0.5"
        android:toYScale="0.5" />
</set>

2.通过AnimationUtils.loadAnimation方法获取Animation对象让控件开始动画:

        Animation animation = AnimationUtils.loadAnimation(this, R.anim.animation_set);
        bt_animation1.startAnimation(animation);
  • java动态执行动画:
//动态
        bt_animation2 = (Button) findViewById(R.id.bt_animation2);
        AnimationSet animationSet = new AnimationSet(true);
        //子动画一
        Animation animation1 = new AlphaAnimation(0, 1);
        animation1.setDuration(1000);
        //子动画二
        Animation animation2 = new TranslateAnimation(0, 500, 0, 0);
        animation2.setDuration(2000);
        animation2.setStartOffset(3000);
        //子动画三
        Animation animation3 = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        animation3.setDuration(3000);
        animation3.setRepeatMode(Animation.RESTART);
        animation3.setRepeatCount(Animation.INFINITE);
        //子动画四
        Animation animation4 = new ScaleAnimation(1, 0.5f, 1, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        animation4.setDuration(3000);
        animation4.setStartOffset(4000);

        animationSet.addAnimation(animation1);
        animationSet.addAnimation(animation2);
        animationSet.addAnimation(animation3);
        animationSet.addAnimation(animation4);
        bt_animation2.startAnimation(animationSet);

这样就能实现组合动画。
动画监听
通过setAnimationListener得到动画监听回调,开始和结束

animation2.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {

            }

            @Override
            public void onAnimationEnd(Animation animation) {

            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });

四.属性动画

我们知道帧动画和补间动画都只是改变视觉效果,并没有真正改变控件的属性,因此我们接触到了属性动画,属性动画中一些类的继承关系如下:

属性动画

我们可以着重看到ValueAnimator,ObjectAnimator和AnimatorSet三个类,因此,属性动画主要围绕这三个类展开,看看属性动画是怎么实现的。
ValueAnimator
通过不断控制值的变化,变化过程中再不断手动赋给对象的属性,从而实现动画效果。
它有三个主要的方法:ValueAnimator.ofInt(int values),ValueAnimator.oFloat(float values)和ValueAnimator.ofObject()。
1.ValueAnimator.ofInt(int values):
它的参数可以传入多个int值,表示多个int值之间进行一个平滑过渡,得到一个动画实例,通过动画的更新监听器将平滑过渡的值传给控件来改变控件的属性打到动画效果。
缩放效果:

bt_value1 = (Button) findViewById(R.id.bt_value1);
        //步骤1.创建动画实例,将传入的多个Int参数进行平滑过渡,这里只有两个int参数,可以有多个
        ValueAnimator valueAnimator = ValueAnimator.ofInt(bt_value1.getLayoutParams().width, 500);
        //步骤2.设置动画的播放各种属性,如动画运行的时长setDuration,动画延迟播放时间setStartDelay,动画重复播放次数setRepeatCount,重复播放动画模式setRepeatMode
        valueAnimator.setDuration(3000);
        //步骤3.将改变的值手动赋值给对象的属性值:通过动画的更新监听器,值每次改变、变化一次,该方法就会被调用一次
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                int currentValue = (int) valueAnimator.getAnimatedValue();
                bt_value1.getLayoutParams().width = currentValue;//将当前的值给button作为宽度
                bt_value1.requestLayout();//对button进行重新绘制
            }
        });
        //步骤4.开启动画
        valueAnimator.start();

平移效果:

bt_value2 = (Button) findViewById(R.id.bt_value2);
        ValueAnimator valueAnimator2 = ValueAnimator.ofInt(0, 300);
        valueAnimator2.setDuration(3000);
        valueAnimator2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                int currentMargin = (int) valueAnimator.getAnimatedValue();
                RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(bt_value2.getLayoutParams());
                layoutParams.setMargins(currentMargin, 0, 0, 0);
                bt_value2.setLayoutParams(layoutParams);
            }
        });
        valueAnimator2.start();

透明度效果:

bt_value3 = (Button) findViewById(R.id.bt_value3);
        ValueAnimator valueAnimator3 = ValueAnimator.ofFloat(0, 1);
        valueAnimator3.setDuration(3000);
        valueAnimator3.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                float currentValue = (float) valueAnimator.getAnimatedValue();
                bt_value3.setAlpha(currentValue);
                bt_value3.requestLayout();
            }
        });
        valueAnimator3.start();

接下来主要讲一下ValueAnimator.ofObject()方法的使用。
2.ValueAnimator.ofObject(TypeEvaluator evaluator,Object object):
在补间动画的时候我们有一个interpolator属性是用来设置插值器的用于设置 属性值 从初始值过渡到结束值 的变化规律,诸如减速,加速,匀速,先减速在加速等等这些。该方法的第一个参数是TypeEvaluator表示的是估值器用于设置 属性值 从初始值过渡到结束值 的变化具体数值,也就是根据时间的进度获取该方法第二个参数和第三个参数在变化过程中的数值的方法。前面的ofInt是作用于int数值,ofFloat是作用于Float数值,所以ofObject是作用于对象,我们先创建一个实例对象Point表示控件距离左侧和上侧控件的边距:

public class Point {

    // 设置两个变量用于记录控件距离左侧和上侧控件的边距
    private int x;
    private int y;

    // 构造方法用于设置边距
    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    // get方法用于获取边距
    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }
}

然后自定义估值器PointEvaluator用于获取根据时间变化过程中的对象objec:

// 实现TypeEvaluator接口
public class PointEvaluator implements TypeEvaluator {

    // 复写evaluate()
    // 在evaluate()里写入对象动画过渡的逻辑
    @Override
    public Object evaluate(float fraction, Object startValue, Object endValue) {

        // 将动画初始值startValue 和 动画结束值endValue 强制类型转换成Point对象
        Point startPoint = (Point) startValue;
        Point endPoint = (Point) endValue;

        // 根据fraction来计算当前动画的x和y的值
        int x = (int) (startPoint.getX() + fraction * (endPoint.getX() - startPoint.getX()));
        int y = (int) (startPoint.getY() + fraction * (endPoint.getY() - startPoint.getY()));

        // 将计算后的坐标封装到一个新的Point对象中并返回
        Point point = new Point(x, y);
        return point;
    }
}

我们创建初始对象startPoint和结束对象endPoint,在变化过程中获取当前point对象并给Button设置距离左侧和上侧控件的边距如下:

        bt = (Button) findViewById(R.id.bt);
        Point startPoint = new Point(0, 0);
        Point endPoint = new Point(500, 500);
        ValueAnimator valueAnimator = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);
        valueAnimator.setDuration(3000);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                Point currentPoint = (Point) valueAnimator.getAnimatedValue();
                RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(bt.getLayoutParams());
                lp.setMargins(currentPoint.getX(), currentPoint.getY(), 0, 0);
                bt.setLayoutParams(lp);
                bt.requestLayout();
            }
        });
        valueAnimator.start();

这样就实现了Button在3秒时间里从startPoint到endPoint边距的变化过程的动画,这就是ValueAnimator.ofObject的使用
ObjectAnimator
直接对对象的属性值进行改变操作,从而实现动画效果。用法上和ValueAnimator比较类似:
先看下面的对控件进行透明度,平移,缩放和旋转的动画:

        bt_alpha = (Button) findViewById(R.id.bt_alpha);
        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(bt_alpha, "alpha", 0, 1);
        objectAnimator.setDuration(3000);
        objectAnimator.start();

        bt_translate = (Button) findViewById(R.id.bt_translate);
        ObjectAnimator.ofFloat(bt_translate, "translationX", bt_translate.getTranslationX(), 300, bt_translate.getTranslationX()).setDuration(3000).start();


        bt_scale = (Button) findViewById(R.id.bt_scale);
        ObjectAnimator.ofFloat(bt_scale, "scaleX", 0, 2, 1).setDuration(3000).start();

        bt_rotate = (Button) findViewById(R.id.bt_rotate);
        ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(bt_rotate, "rotationY", 0, 360).setDuration(3000);
        objectAnimator2.setRepeatCount(ValueAnimator.INFINITE);
        objectAnimator2.start();

注意上面ObjectAnimator.ofFloat方法中的第二个参数决定了对控件什么操作,参数名称对应作用见下表:

属性 作用 数值类型
Alpha 控制View的透明度 float
TranslationX 控制X方向的位移 float
TranslationY 控制Y方向的位移 float
ScaleX 控制X方向的缩放倍数 float
ScaleY 控制Y方向的缩放倍数 float
Rotation 控制以屏幕方向为轴的旋转度数 float
RotationX 控制以X轴为轴的旋转度数 float
RotationY 控制以Y轴为轴的旋转度数 float

注意:ObjectAnimator是对对象的属性值进行改变操作,那么要动画生效,必须满足两个条件:
1.对象必须要提供属性a的set()方法,而且如果没传递初始值,那么需要提供get()方法,因为系统要去拿属性a的初始值
2.属性a的set()方法 对 属性a的改变带来ui上的变化
只有同时满足上面两个条件,动画才会生效。那么如果不满足上面两个条件但是想用怎么办,有两种方法:
1.通过继承原始类,直接给类加上该属性的 get()& set(),从而实现给对象加上该属性的 get()& set()
2.通过包装原始动画对象,间接给对象加上该属性的 get()&set()。即 用一个类来包装原始对象。
比如,width这个属性,虽然控件有set和get的方法,但是控件的set方法并不是设置控件宽度用的,而是设置控件最大宽度和最小宽度的,因此无法去改变控件的宽度,自然动画无法生效。我们可以使用第二种方法进行包装来进行动画改变控件的宽度。先自定义类ViewWrapper添加对View宽度的set个get方法:

public class ViewWrapper {
        View view;

        public ViewWrapper(View view) {
            this.view = view;
        }

        //得到控件的宽度
        public int getWidth() {
            return view.getLayoutParams().width;
        }

        //设置控件的宽度
        public void setWidth(int width) {
            view.getLayoutParams().width = width;
            view.requestLayout();
        }
    }

在使用ObjectAnimator对ViewWrapper 对象的width属性进行动态改变也就改变了控件的宽度从而达到动画的效果:

        bt = (Button) findViewById(R.id.bt);
        ViewWrapper viewWrapper = new ViewWrapper(bt);
        ObjectAnimator animator = ObjectAnimator.ofInt(viewWrapper, "width", 0, 500);
        animator.setDuration(3000);
        animator.start();

AnimatorSet
AnimatorSet是组合动画,毕竟淡一点动画还是比较少,很多时候动画都是由单一的属性动画组合在一起。AnimatorSet的使用有如下方法:

AnimatorSet.play(Animator anim)   :播放当前动画
AnimatorSet.after(long delay)   :将现有动画延迟delay毫秒后执行
AnimatorSet.with(Animator anim)   :将现有动画和传入的动画同时执行
AnimatorSet.after(Animator anim)   :将现有动画插入到传入的动画之后执行
AnimatorSet.before(Animator anim) :  将现有动画插入到传入的动画之前执行

比如我们需要一个延迟一秒后,先透明度由0-1,然后平移加旋转加缩放的动画:

        bt2= (Button) findViewById(R.id.bt2);
        //子动画一
        ObjectAnimator objectAnimator=ObjectAnimator.ofFloat(bt2,"alpha",0,1);
        objectAnimator.setDuration(2000);
        //子动画二
        ObjectAnimator objectAnimator2=ObjectAnimator.ofFloat(bt2,"translationX",0,300);
        objectAnimator2.setDuration(3000);
        //子动画三
        ObjectAnimator objectAnimator3=ObjectAnimator.ofFloat(bt2,"rotation",0,360);
        objectAnimator3.setDuration(3000);
        //子动画四
        ObjectAnimator objectAnimator4=ObjectAnimator.ofFloat(bt2,"scaleX",1,0.5f);
        objectAnimator4.setDuration(3000);
        //子动画五
        ObjectAnimator objectAnimator5=ObjectAnimator.ofFloat(bt2,"scaleY",1,0.5f);
        objectAnimator5.setDuration(3000);

        AnimatorSet animatorSet=new AnimatorSet();
        animatorSet.play(objectAnimator2).with(objectAnimator3).with(objectAnimator4).with(objectAnimator5).after(objectAnimator).after(1000);
        animatorSet.start();

ViewPropertyAnimator
属性动画最终都是对控件的值属性进行操作,因此,谷歌也开放了直接用控件进行动画的方法,可以认为是属性动画的简便操作方式:View.animate().xxx();View.animate()返回的是ViewPropertyAnimator,后面调用的方法都是在ViewPropertyAnimator的基础上进行调用开启动画,但是不需要调用start方法去启动。

        bt3 = (Button) findViewById(R.id.bt3);
//        bt3.animate().alpha(0).setDuration(3000);//透明度由原来变为0
//        bt3.animate().translationX(300).setDuration(3000);//平移
//        bt3.animate().scaleX(0.5f).scaleY(0.5f).setDuration(3000);//X,Y缩放为原来0.5
        bt3.animate().rotation(360).setDuration(3000);//顺时针旋转360度

动画监听
通过addListener添加动画监听得到动画开始,结束,取消方法回调

animator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {

            }

            @Override
            public void onAnimationEnd(Animator animator) {

            }

            @Override
            public void onAnimationCancel(Animator animator) {

            }

            @Override
            public void onAnimationRepeat(Animator animator) {

            }
        });

当然,可以使用AnimatorListenerAdapter只监听开始或者结束的其中一个方法:

animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
            }
        });

以上就是属性动画相关的用法。

五.总结

以上就是关于Android帧动画,补间动画和属性动画的相关知识点,如有不足或者错误的地方请在下方指正。我们需要多看更需要多写,只有不断学习,不断进步才能不被淘汰。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,165评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,720评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,849评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,245评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,596评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,747评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,977评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,708评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,448评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,657评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,141评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,493评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,153评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,890评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,799评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,685评论 2 272

推荐阅读更多精彩内容