Android 动画(七)AnimatorSet组合动画

概述:

ValueAnimator和ObjectAnimator都是针对单个动画的,虽然可以用PropertyValuesHolder实现一个View的多种动画,但是没办法实现多个View同时动画。如果要对多个View做动画,并且单个View上存在多种动画效果,这时候就要用到AnimatorSet类了。AnimatorSet类用来实现复杂的组合动画,但功能上相比于AnimationSet强大多了。AnimatorSet针对ValueAnimator和ObjectAnimator都是适用的,但一般而言,基本不会用到ValueAnimator的组合动画。

一、AnimatorSet

在AnimatorSet中给为我们提供了两个方法playSequentially和playTogether,

  • playSequentially表示所有动画依次播放
  • playTogether表示所有动画一起开始

1.1 playSequentially

playSequentially的声明如下:

public void playSequentially(Animator... items);
public void playSequentially(List<Animator> items);

这里有两个声明方法,第一个是最常用的,它的参数是可变长参数,也就是说我们可以传进去任意多个Animator对象。这些对象的动画会逐个播放。
第二个构造方法,是传进去一个List< Animator>的列表。原理一样,也是逐个去取List中的动画对象,然后逐个播放。
下面代码演示使用第一种构造方法:

    /**
     * 设置多个View顺序播放动画
     *
     */
    private void startPlaySequentiallyAnim() {
        ObjectAnimator objectAnimator01 = ObjectAnimator.ofArgb(ivImage01, "BackgroundColor",
                getResources().getColor(R.color.colorPrimary),
                getResources().getColor(R.color.colorAccent),
                getResources().getColor(R.color.colorPrimary));
        ObjectAnimator objectAnimator02 = ObjectAnimator.ofFloat(ivImage01, "TranslationY", 0, 300, 0);
        ObjectAnimator objectAnimator03 = ObjectAnimator.ofFloat(ivImage02, "TranslationY", 0, 400, 0);
        ObjectAnimator objectAnimator04 = ObjectAnimator.ofFloat(ivImage03, "TranslationY", 0, 500, 0);
        ObjectAnimator objectAnimator05 = ObjectAnimator.ofFloat(ivImage04, "TranslationY", 0, 600, 0);

        AnimatorSet animatorSet=new AnimatorSet();
        animatorSet.playSequentially(objectAnimator01,objectAnimator02,objectAnimator03,objectAnimator04,objectAnimator05);
        animatorSet.setDuration(2000);
        animatorSet.start();
    }

效果如下:
这里写图片描述

1.2 playTogether

playTogether表示将所有动画一起播放
playTogether的声明如下:

public void playTogether(Animator... items);
public void playTogether(Collection<Animator> items);

有两个声明方法,区别只是传入的参数不一样
第一个是传可变长参数列表
第二个则是需要传一个组装好的Collection对象。
下面代码演示使用第一种构造方法:

    /**
     * 设置多个View一起播放动画
     */
    private void startPlayTogetherAnim() {
        ObjectAnimator objectAnimator01 = ObjectAnimator.ofArgb(ivImage05, "BackgroundColor",
                getResources().getColor(R.color.colorPrimary),
                getResources().getColor(R.color.colorAccent),
                getResources().getColor(R.color.colorPrimary));
        ObjectAnimator objectAnimator02 = ObjectAnimator.ofFloat(ivImage05, "TranslationY", 0, 300, 0);
        ObjectAnimator objectAnimator03 = ObjectAnimator.ofFloat(ivImage06, "TranslationY", 0, 400, 0);
        ObjectAnimator objectAnimator04 = ObjectAnimator.ofFloat(ivImage07, "TranslationY", 0, 500, 0);
        ObjectAnimator objectAnimator05 = ObjectAnimator.ofFloat(ivImage08, "TranslationY", 0, 600, 0);

        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.playTogether(objectAnimator01, objectAnimator02, objectAnimator03, objectAnimator04, objectAnimator05);
        animatorSet.setDuration(2000);
        animatorSet.start();
    }

动画效果:

这里写图片描述

实现无限循环动画:

示例代码:

    /**
     * 设置多个View一起播放无限循环动画
     */
    private AnimatorSet startInfiniteLoopAnim() {
        ObjectAnimator objectAnimator01 = ObjectAnimator.ofArgb(ivImage09, "BackgroundColor",
                getResources().getColor(R.color.colorPrimary),
                getResources().getColor(R.color.colorAccent),
                getResources().getColor(R.color.colorPrimary));
        objectAnimator01.setRepeatCount(ValueAnimator.INFINITE);
        ObjectAnimator objectAnimator02 = ObjectAnimator.ofFloat(ivImage09, "TranslationY", 0, 300, 0);
        objectAnimator02.setRepeatCount(ValueAnimator.INFINITE);
        ObjectAnimator objectAnimator03 = ObjectAnimator.ofFloat(ivImage10, "TranslationY", 0, 400, 0);
        objectAnimator03.setRepeatCount(ValueAnimator.INFINITE);
        ObjectAnimator objectAnimator04 = ObjectAnimator.ofFloat(ivImage11, "TranslationY", 0, 500, 0);
        objectAnimator04.setRepeatCount(ValueAnimator.INFINITE);
        ObjectAnimator objectAnimator05 = ObjectAnimator.ofFloat(ivImage12, "TranslationY", 0, 600, 0);
        objectAnimator05.setRepeatCount(ValueAnimator.INFINITE);

        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.playTogether(objectAnimator01, objectAnimator02, objectAnimator03, objectAnimator04, objectAnimator05);
        animatorSet.setDuration(2000);
        animatorSet.start();
        return animatorSet;
    }

动画效果:
这里写图片描述

playTogether和playSequentially在激活动画后,控件的动画情况与它们无关,它们只负责定时激活控件动画。
playSequentially只有上一个控件做完动画以后,才会激活下一个控件的动画,如果上一控件的动画是无限循环,那下一个控件就无法做动画了。

1.3 AnimatorSet.Builder(自由设置动画顺序)

AnimatorSet.Builder用于实现playTogether和playSequentially无法实现的效果,可以实现非常自由的组合动画,比如有三个动画A,B,C想先播放C然后同时播放A和B,利用playTogether和playSequentially是没办法实现的,但利用AnimatorSet.Builder却可以轻易实现。

1.3.1 AnimatorSet.Builder常用方法
方法 概述
public Builder play(Animator anim) 表示要播放哪个动画
AnimatorSet中的play方法是获取AnimatorSet.Builder对象的唯一途径
public Builder with(Animator anim) 和前面动画一起执行
public Builder before(Animator anim) 执行前面的动画后才执行该动画
public Builder after(Animator anim) 执行先执行这个动画再执行前面动画
public Builder after(long delay) 延迟n毫秒之后执行动画

play(Animator anim)表示当前在播放哪个动画,另外的with(Animator anim)、before(Animator anim)、after(Animator anim)都是以play中的当前所播放的动画为基准的。
当play(playAnim)与before(beforeAnim)共用,则表示在播放beforeAnim之前,先播放playAnim动画;同样,当play(playAnim)与after(afterAnim)共用时,则表示在在播放afterAnim动画之后,再播放playAnim动画。

示例代码:

    /**
     * 按照自定义顺序播放动画
     * 首先ivImage09的颜色变化、位移和ivImage09,同时发生
     * 等待前面的动画播放完后 ivImage11,ivImage12才开始动画
     *
     */
    private void startCustomOrderAnim() {
        ObjectAnimator objectAnimator01=ObjectAnimator.ofArgb(ivImage09, "BackgroundColor",
                getResources().getColor(R.color.colorPrimary),
                getResources().getColor(R.color.colorAccent),
                getResources().getColor(R.color.colorPrimary));
        ObjectAnimator objectAnimator02 = ObjectAnimator.ofFloat(ivImage09, "TranslationY", 0, 300, 0);
        ObjectAnimator objectAnimator03 = ObjectAnimator.ofFloat(ivImage10, "TranslationY", 0, 400, 0);
        ObjectAnimator objectAnimator04 = ObjectAnimator.ofFloat(ivImage11, "TranslationY", 0, 500, 0);
        ObjectAnimator objectAnimator05 = ObjectAnimator.ofFloat(ivImage12, "TranslationY", 0, 600, 0);

        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.play(objectAnimator01).with(objectAnimator02).with(objectAnimator03).before(objectAnimator04).before(objectAnimator05);
        animatorSet.setDuration(2000);
        animatorSet.start();
    }

动画效果:
这里写图片描述

1.4 AnimatorSet监听器

在AnimatorSet中也可以添加监听器,添加方法为:
public void addListener(AnimatorListener listener);

AnimatorSet的监听:

  • AnimatorSet的监听函数也只是用来监听AnimatorSet的状态的,与其中的动画无关;
  • AnimatorSet中没有设置循环的函数,所以AnimatorSet监听器中永远无法运行到onAnimationRepeat()中!
public static interface AnimatorListener {
    /**
     * 当AnimatorSet开始时调用
     */
    void onAnimationStart(Animator animation);
/**
     * 当AnimatorSet结束时调用
     */
    void onAnimationEnd(Animator animation);
/**
     * 当AnimatorSet被取消时调用
     */
    void onAnimationCancel(Animator animation);
/**
     * 当AnimatorSet重复时调用,由于AnimatorSet没有设置repeat的函数,所以这个方法永远不会被调用
     */
    void onAnimationRepeat(Animator animation);
}

1.5 AnimatorSet常用方法

方法 概述
public AnimatorSet setDuration(long duration) 设置单次动画时长
public void setInterpolator(TimeInterpolator interpolator) 设置插值器
public void setTarget(Object target) 设置ObjectAnimator动画目标控件
public void setStartDelay(long startDelay) 设置AnimatorSet动画延迟激活时间

由于在ObjectAnimator中也存在以上方法,在AnimatorSet中设置以后,会覆盖单个ObjectAnimator中的设置;即如果AnimatorSet中没有设置,那么就以ObjectAnimator中的设置为准。如果AnimatorSet中设置以后,ObjectAnimator中的设置就会无效。例如:AnimatorSet.setTarget()的作用就是将动画的目标统一设置为当前控件,AnimatorSet中的所有动画都将作用在所设置的target控件上。但唯一的例外就是setStartDelay。
setStartDelay函数不会覆盖单个动画的延时,而且仅针对性的延长AnimatorSet的激活时间,单个动画的所设置的setStartDelay仍对单个动画起作用。

注意:

  1. AnimatorSet的延时是仅针对性的延长AnimatorSet激活时间的,对单个动画的延时设置没有影响。
  2. 在使用with的情况下,AnimatorSet的激活时间跟单个动画没有关系,激活后所有动画同时开始,包括延迟

下面两个例子可以好好体会下:

    /**
     *  animatorSet 设置激活动画延时时长
        我们首先给animatorSet设置了2秒后开始激活动画,而objectAnimator02设置了2秒启动延时,objectAnimator03/04/05都没有设置延时
        所以objectAnimator02在animatorSet激活动画2秒后才会运动,objectAnimator03/04/05在animatorSet激活动画后,就会开始运动。
     */
    private void startDelay01Anim() {

        ObjectAnimator objectAnimator02 = ObjectAnimator.ofFloat(ivImage09, "TranslationY", 0, 300, 0);
        objectAnimator02.setStartDelay(2000);
        ObjectAnimator objectAnimator03 = ObjectAnimator.ofFloat(ivImage10, "TranslationY", 0, 400, 0);
        ObjectAnimator objectAnimator04 = ObjectAnimator.ofFloat(ivImage11, "TranslationY", 0, 500, 0);
        ObjectAnimator objectAnimator05 = ObjectAnimator.ofFloat(ivImage12, "TranslationY", 0, 600, 0);

        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.play(objectAnimator02).with(objectAnimator03).with(objectAnimator04).with(objectAnimator05);
        animatorSet.setStartDelay(2000);
        animatorSet.setDuration(2000);
        animatorSet.start();
    }

这里写图片描述



   /**
     *  animatorSet 设置激活动画延时时长
        我们首先给animatorSet设置了2秒后激活动画,而objectAnimator02没有设置启动延时,所以在animatorSet激活动画后objectAnimator02马上开始运动,而objectAnimator03/04/05
        都设置2秒启动延时,并跟随objectAnimator02一起运动,所以会在animatorSet激活动画并延时2秒后,才开始动画。
     */
    private void startDelay02Anim() {

        ObjectAnimator objectAnimator02 = ObjectAnimator.ofFloat(ivImage09, "TranslationY", 0, 300, 0);
        ObjectAnimator objectAnimator03 = ObjectAnimator.ofFloat(ivImage10, "TranslationY", 0, 400, 0);
        objectAnimator03.setStartDelay(2000);
        ObjectAnimator objectAnimator04 = ObjectAnimator.ofFloat(ivImage11, "TranslationY", 0, 500, 0);
        objectAnimator04.setStartDelay(2000);
        ObjectAnimator objectAnimator05 = ObjectAnimator.ofFloat(ivImage12, "TranslationY", 0, 600, 0);
        objectAnimator05.setStartDelay(2000);

        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.play(objectAnimator02).with(objectAnimator03).with(objectAnimator04).with(objectAnimator05);
        animatorSet.setStartDelay(2000);
        animatorSet.setDuration(2000);
        animatorSet.start();
    }

这里写图片描述

二、AnimatorSet XML实现

2.1 xml标签与java类的对应关系

XML标签 java类
<animator /> ValueAnimator
<objectAnimator /> ObjectAnimator
<set /> AnimatorSet

2.2 animator字段详解

- -
<animator/> <animator
android:duration=”int”
ndroid:valueFrom=”float | int | color”
ndroid:valueTo=”float | int | color”
ndroid:startOffset=”int”
ndroid:repeatCount=”int”
ndroid:repeatMode=[“repeat” | “reverse”]
ndroid:valueType=[“intType” | “floatType”]
ndroid:interpolator=[“@android:anim/xxx”]/>
android:duration: 每次动画播放的时长
android:valueFrom: 初始动化值;取值范围为float,int和color,如果取值为float对应的值样式应该为89.0,取值为Int时,对应的值样式为:89;当取值为clolor时,对应的值样式为 #333333;
android:valueTo: 动画结束值;取值范围同样是float,int和color这三种类型的值;
android:startOffset: 动画激活延时;对应代码中的startDelay(long delay)函数;
android:repeatCount: 动画重复次数
android:repeatMode: 动画重复模式,取值为repeat和reverse;repeat表示正序重播,reverse表示倒序重播
android:valueType: 表示参数值类型,取值为intType和floatType;与android:valueFrom、android:valueTo相对应。如果这里的取值为intType,那么android:valueFrom、android:valueTo的值也就要对应的是int类型的数值。如果这里的数值是floatType,那么android:valueFrom、android:valueTo的值也要对应的设置为float类型的值。
注意:如果android:valueFrom、android:valueTo的值设置为color类型的值,那么不需要设置这个参数;
android:interpolator: 设置加速器/插值器;

示例代码:
animator/anim_animator.xml:

<?xml version="1.0" encoding="utf-8"?>
<animator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:valueType="floatType"
    android:valueFrom="0.1"
    android:valueTo="1.0"
    android:interpolator="@android:anim/bounce_interpolator">
</animator>
    /**
     * 使用AnimatorInflater.loadAnimator()加载xml中定义的ValueAnimator动画
     */
    private void loadXmlAnimator(){
        ValueAnimator valueAnimator=(ValueAnimator) AnimatorInflater.loadAnimator(this,R.animator.anim_animator);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float value=(float)animation.getAnimatedValue();
                ivImage01.setScaleX(value);
                ivImage01.setScaleY(value);
            }
        });
        valueAnimator.start();
    }

动画效果:
这里写图片描述

2.3 objectAnimator字段详解

- -
objectAnimator <objectAnimator
ndroid:propertyName=”string”
ndroid:duration=”int”
ndroid:valueFrom=”float | int |color”
ndroid:valueTo=”float | int | color”
ndroid:startOffset=”int”
ndroid:repeatCount=”int”
ndroid:repeatMode=[“repeat” | “reverse”]
ndroid:valueType=[“intType” | “floatType”]
ndroid:interpolator=[“@android:anim/xxx”]/>
android:propertyName: 对应属性名,即ObjectAnimator所需要操作的属性名。
android:duration: 每次动画播放的时长
android:valueFrom: 初始动化值;取值范围为float,int和color;
android:valueTo: 动画结束值;取值范围同样是float,int和color这三种类型的值;
android:startOffset: 动画激活延时;对应代码中的startDelay(long delay)函数;
android:repeatCount: 动画重复次数
android:repeatMode: 动画重复模式,取值为repeat和reverse;repeat表示正序重播,reverse表示倒序重播
android:valueType: 表示参数值类型,取值为intType和floatType;与android:valueFrom、android:valueTo相对应。如果这里的取值为intType,那么android:valueFrom、android:valueTo的值也就要对应的是int类型的数值。如果这里的数值是floatType,那么android:valueFrom、android:valueTo的值也要对应的设置为float类型的值。非常注意的是,如果android:valueFrom、android:valueTo的值设置为color类型的值,那么不需要设置这个参数;
android:interpolator: 设置加速器;

示例代码01:
animator/anim_object_animator.xml

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1500"
    android:propertyName="TranslationX"
    android:valueFrom="0"
    android:valueTo="400"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    android:repeatCount="1"
    android:repeatMode="reverse"
    android:startOffset="1000">
</objectAnimator>

java:

    /**
     * 使用AnimatorInflater.loadAnimator()加载xml中定义的ObjectAnimator动画
     */
    private void loadXmlObjectAnimator(){
        ObjectAnimator objectAnimator=(ObjectAnimator) AnimatorInflater.loadAnimator(this,R.animator.anim_object_animator);
        objectAnimator.setTarget(ivImage02);
        objectAnimator.start();
    }

动画效果:
这里写图片描述

示例代码02:
animator/anim_object_animator_color.xml

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="2000"
    android:propertyName="BackgroundColor"
    android:valueFrom="@color/colorAccent"
    android:valueTo="@color/colorPrimary"
    android:repeatCount="1"
    android:repeatMode="reverse">

</objectAnimator>

java代码:

    /**
     * 使用AnimatorInflater.loadAnimator()加载xml中定义的ObjectAnimator color动画
     */
    private void loadXmlObjectAnimatorColor(){
        ObjectAnimator objectAnimator=(ObjectAnimator) AnimatorInflater.loadAnimator(this,R.animator.anim_object_animator_color);
        objectAnimator.setEvaluator(new ArgbEvaluator());
        objectAnimator.setTarget(ivImage02);
        objectAnimator.start();
    }

动画效果:
这里写图片描述

2.4 set字段详解

字段意义及使用方法

- -
android:ordering [“together” |”sequentially”]
android:ordering:表示动画开始顺序。together表示同时开始动画,sequentially表示逐个开始动画;

示例代码:
animator/anim_animator_set.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:ordering="together">

    <objectAnimator android:duration="1500"
                    android:propertyName="TranslationX"
                    android:valueFrom="0"
                    android:valueTo="400"
                    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
                    android:repeatCount="1"
                    android:repeatMode="reverse"
                    android:startOffset="1000"/>

    <objectAnimator android:duration="2000"
                    android:propertyName="BackgroundColor"
                    android:valueFrom="@color/colorAccent"
                    android:valueTo="@color/colorPrimary"
                    android:repeatCount="1"
                    android:repeatMode="reverse"
                    android:valueType="colorType"/>

</set>

java代码:

    /**
     * 使用AnimatorInflater.loadAnimator()加载xml中定义的AnimatorSet动画
     */
    private void loadXmlAnimatorSet(){
        AnimatorSet animatorSet=(AnimatorSet) AnimatorInflater.loadAnimator(this,R.animator.anim_animator_set);
        animatorSet.setTarget(ivImage02);
        animatorSet.start();
    }

动画效果:
这里写图片描述




到此Android的动画部分,就学习完结了,总共7篇,由浅至深的学习了android的动画部分,当然了只是一些基础部分,剩下还要在实战中继续提高。(PS:虽然动画部分上个月就学习完了,但由于时间紧张,工作也比较忙,间隔一个月后才陆陆续续的总结完毕。),后续也会在博客中放一些动画例子。

猜你喜欢

转载自blog.csdn.net/MakerCloud/article/details/82082124
今日推荐