Android 动画(七)AnimatorSet组合动画

本文深入探讨Android的AnimatorSet,介绍了如何通过playSequentially和playTogether实现动画顺序播放和同时播放。此外,还讲解了AnimatorSet.Builder如何实现更复杂的动画组合,并提供了监听器和常用方法的使用示例。最后,文章讨论了AnimatorSet XML实现,包括animator、objectAnimator和set字段的详细解析。

概述:

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:虽然动画部分上个月就学习完了,但由于时间紧张,工作也比较忙,间隔一个月后才陆陆续续的总结完毕。),后续也会在博客中放一些动画例子。

评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值