Android动画篇(六)—— 组合动画AnimatorSet和PropertyValuesHolder的使用

前言:把握生命里的每一分钟,全力以赴心中的梦。不经历风雨,怎么见彩虹,没有人能随随便便成功。----《真心英雄》
一、概述 我们在上一篇文章中已经详细讲解了ObjectAnimator的使用,但是ValueAnimator和ObjectAnimator只能简单实现一个动画,如果我要实现一个组合动画呢?比如一边缩放,一边移动那怎么办?系统也提供了一个AnimatorSet属性动画组合类,由于ValueAnimator比较少用到,这里就讲解ObjectAnimator配合AnimatorSet的使用。另外,这里最后增加了PropertyValuesHolder用法的讲解。
1、基本属性
AnimatorSet继承自Animator类,Animator类有的属性AnimatorSet都有,这里列出常用的一部分函数:
/** * 开启动画 */ void start() /** * 设置动画时间 */ AnimatorSet setDuration(long duration) /** * 退出动画 */ void cancel() /** * 设置插值器 */ void setInterpolator(TimeInterpolator interpolator)

监听器:
/** * 监听器一:监听动画变化时四个状态 */ public static interface AnimatorListener { void onAnimationStart(Animator animation); void onAnimationEnd(Animator animation); void onAnimationCancel(Animator animation); void onAnimationRepeat(Animator animation); } //添加方法为:public void addListener(AnimatorListener listener) /** *监听器二:监听动画暂停和暂停后再恢复的状态 */ public static interface AnimatorPauseListener { void onAnimationPause(Animator animation); void onAnimationResume(Animator animation); } //添加方法:public void addPauseListener(AnimatorPauseListener listener)

这些属性在《Android动画篇(三)—— 属性动画ValueAnimator的使用》已经作了详细解释,这里就不一一细讲了。

二、基本使用 1、示例
ObjectAnimator color = ObjectAnimator.ofArgb(mTextView1, "backgroundColor", 0xffff00ff, 0xffffff00, 0xff0000ff); color.setEvaluator(new ArgbEvaluator()); ObjectAnimator translation = ObjectAnimator.ofFloat(mTextView1, "translationY", 0f, 400f, 0f); //构建AnimatorSet实例 AnimatorSet animatorSet= new AnimatorSet(); animatorSet.playTogether(color, translation); //添加动画监听 animatorSet.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { Log.e(TAG, "onAnimationStart"); }@Override public void onAnimationEnd(Animator animation) { Log.e(TAG, "onAnimationEnd"); }@Override public void onAnimationCancel(Animator animation) { Log.e(TAG, "onAnimationCancel"); }@Override public void onAnimationRepeat(Animator animation) { Log.e(TAG, "onAnimationRepeat"); } }); //设置动画时长 animatorSet.setDuration(2000); //开启动画 animatorSet.start();

效果如下:
Android动画篇(六)—— 组合动画AnimatorSet和PropertyValuesHolder的使用
文章图片

从图中可以看出,我们设置了两个动画,一个颜色渐变,一个向下移动,调用playTogether()函数后,两个动画都同时启动了。
2、playTogether和playSequentially
(1)playTogether
  • playTogether(Animator... items)同时开启动画,参数是可变长参数,参数为需要执行的动画
  • playTogether(Collection items)同时开启动画,参数是动画合集
这里的函数都是一样的,只是参数不一样,第一个传入的是可变长参数,第二个传入的是集合Collection items,我们来看看playTogether的用法:
ObjectAnimator color = ObjectAnimator.ofArgb(mTextView1, "backgroundColor", 0xffff00ff, 0xffffff00, 0xff0000ff); color.setEvaluator(new ArgbEvaluator()); ObjectAnimator translation = ObjectAnimator.ofFloat(mTextView1, "translationY", 0f, 400f, 0f); ObjectAnimator translation2 = ObjectAnimator.ofFloat(mTextView2, "translationY", 0f, 600f, 0f); //构建AnimatorSet实例 AnimatorSet animatorSet = new AnimatorSet(); animatorSet.playTogether(color, translation, translation2); //设置动画时长 animatorSet.setDuration(2000); //开启动画 animatorSet.start();

效果图如下:
Android动画篇(六)—— 组合动画AnimatorSet和PropertyValuesHolder的使用
文章图片

从图中可以看出,开启动画的时候,三个动画时同时执行的,tv1的背景颜色变化和位移以及tv2的位移都是同时开始。
(2)playSequentially
  • playSequentially(Animator... items)逐个播放动画,可变长参数,参数为需要执行的动画
  • playSequentially(List items)逐个播放动画,参数为需要执行的动画的集合
我们来看看使用playSequentially会有怎么样的效果:
ObjectAnimator color = ObjectAnimator.ofArgb(mTextView1, "backgroundColor", 0xffff00ff, 0xffffff00, 0xff0000ff); color.setEvaluator(new ArgbEvaluator()); ObjectAnimator translation = ObjectAnimator.ofFloat(mTextView1, "translationY", 0f, 400f, 0f); ObjectAnimator translation2 = ObjectAnimator.ofFloat(mTextView2, "translationY", 0f, 600f, 0f); //将动画添加到集合中 List animatorList = new ArrayList<>(); animatorList.add(color); animatorList.add(translation); animatorList.add(translation2); //构建AnimatorSet实例 AnimatorSet animatorSet = new AnimatorSet(); animatorSet.playSequentially(animatorList); //设置动画时长 animatorSet.setDuration(2000); //开启动画 animatorSet.start();

效果如下:
Android动画篇(六)—— 组合动画AnimatorSet和PropertyValuesHolder的使用
文章图片

从上面的效果可以看到,动画时一个执行完以后再执行下一个动画,动画合集里面我们是一个个添加进去的,即先加入颜色变化动画,再加入tv1的移动,最后加入tv2的移动动画。调用playSequentially()是将动画组装起来然后依次播放动画。
那么,我们如果第一个动画一直在执行没有结束动画呢?即将第一个动画设置为无限循环,那会是怎么样的效果,我们来看看:
ObjectAnimator color = ObjectAnimator.ofArgb(mTextView1, "backgroundColor", 0xffff00ff, 0xffffff00, 0xff0000ff); color.setEvaluator(new ArgbEvaluator()); //设置循环模式 color.setRepeatMode(ValueAnimator.REVERSE); //设置无限循环 color.setRepeatCount(ValueAnimator.INFINITE); ObjectAnimator translation = ObjectAnimator.ofFloat(mTextView1, "translationY", 0f, 400f, 0f); ObjectAnimator translation2 = ObjectAnimator.ofFloat(mTextView2, "translationY", 0f, 600f, 0f); //将动画添加到集合中 List animatorList = new ArrayList<>(); animatorList.add(color); animatorList.add(translation); animatorList.add(translation2); //构建AnimatorSet实例 AnimatorSet animatorSet = new AnimatorSet(); animatorSet.playSequentially(animatorList); //设置动画时长 animatorSet.setDuration(2000); //开启动画 animatorSet.start();

效果:
Android动画篇(六)—— 组合动画AnimatorSet和PropertyValuesHolder的使用
文章图片

从上面看到,三个动画已经通过playSequentially添加,第一个动画设置了无限循环,开始后永远不会结束,那么下一个动画也就无法开始。
3、AnimatorSet.Builder函数
【Android动画篇(六)—— 组合动画AnimatorSet和PropertyValuesHolder的使用】上面我们知道playTogether和playSequentially能同时开始动画和逐个开始动画,但是如果我想再一个动画开始后,同是开始另外两个动画怎么?系统还提供了一个AnimatorSet.Builder类,这个类是由mAnimatorSet.play(Animator anim)产生的,并且是唯一能产生这个类的方法。我们来看看AnimatorSet.Builder的使用:
(1)常用函数
/** * 表示要播放那个动画 * 获取AnimatorSet.Builder对象的唯一方法 */ public AnimatorSet.Builder play(Animator anim) /** * 表示和前面的动画一起执行 */ public AnimatorSet.Builder with(Animator anim) /** * 表示anim动画在执行Builder动画之后执行(Builder动画在anim动画之前) */ public AnimatorSet.Builder before(Animator anim) /** * 表示anim动画在执行Builder动画之前执行(Builder动画在anim动画之后) */ public AnimatorSet.Builder after(Animator anim) /** * 表示在延迟多少时间后执行该动画,单位为毫秒 */ public AnimatorSet.Builder after(long delay)

(2)示例
我们使用上面的方法做一个例子:
ObjectAnimator color1 = ObjectAnimator.ofArgb(mTextView1, "backgroundColor", 0xffff00ff, 0xffffff00, 0xff0000ff); color1.setEvaluator(new ArgbEvaluator()); ObjectAnimator translation1 = ObjectAnimator.ofFloat(mTextView1, "translationY", 0f, 400f, 0f); ObjectAnimator translation2 = ObjectAnimator.ofFloat(mTextView2, "translationY", 0f, 600f, 0f); ObjectAnimator rotation2 = ObjectAnimator.ofFloat(mTextView2, "rotation", 0f, 360f, 0f); //构建AnimatorSet实例 AnimatorSet animatorSet = new AnimatorSet(); //获取builder实例 AnimatorSet.Builder builder = animatorSet.play(color1); //builder播放动画color1 builder.with(translation1); //跟随builder一起播放translation1 builder.before(translation2); //builder在动画translation2之前播放 builder.after(rotation2); //builder在动画rotation2之后播放//链式写法 //builder.with(translation1).before(translation2).after(rotation2); //设置动画时长 animatorSet.setDuration(2000); //开启动画 animatorSet.start();

效果如下:
Android动画篇(六)—— 组合动画AnimatorSet和PropertyValuesHolder的使用
文章图片

从效果图可以看出,tv2先旋转after(rotation2),然后tv1背景色变化并且向下移动play(color1),with(translation1);最后才执行tv2向下移动before(translation2);
所以以play(color1)中的动画为基准,with(translation1)会跟随play()中的动画一起执行,after(rotation2)是在play()动画之前执行,也就是说rotation2最先执行,before(translation2)在play()之后执行。也可以这样理解:play()动画在after(rotation2)之后执行,play()动画在before(translation2)之前执行,其实就是以谁来定基准而已,谁在谁前后执行,这里比较容易混淆。
我们也可以将这部分的代码简化为链式写法:
builder.with(translation1).before(translation2).after(rotation2);

4、AnimatorSet监听器
我们为AnimatorSet添加监听器,通过addListener(AnimatorListener listener)添加:
ObjectAnimator color = ObjectAnimator.ofArgb(mTextView1, "backgroundColor", 0xffff00ff, 0xffffff00, 0xff0000ff); color.setEvaluator(new ArgbEvaluator()); color.setRepeatCount(ValueAnimator.INFINITE); color.setRepeatMode(ValueAnimator.REVERSE); ObjectAnimator translation = ObjectAnimator.ofFloat(mTextView1, "translationY", 0f, 400f, 0f); //构建AnimatorSet实例 AnimatorSet animatorSet= new AnimatorSet(); animatorSet.playTogether(color, translation); //添加动画监听 animatorSet.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { Log.e(TAG, "onAnimationStart"); }@Override public void onAnimationEnd(Animator animation) { Log.e(TAG, "onAnimationEnd"); }@Override public void onAnimationCancel(Animator animation) { Log.e(TAG, "onAnimationCancel"); }@Override public void onAnimationRepeat(Animator animation) { Log.e(TAG, "onAnimationRepeat"); } }); //设置动画时长 animatorSet.setDuration(2000); //开启动画 animatorSet.start();

注意:监听器必须在start()启动动画之前设置,否则有可能接受不到onAnimationStart(Animator animation)等函数的监听。
点击start anim按钮启动动画,一段时间后点击cancel anim按钮结束动画,效果如下:
Android动画篇(六)—— 组合动画AnimatorSet和PropertyValuesHolder的使用
文章图片

Android动画篇(六)—— 组合动画AnimatorSet和PropertyValuesHolder的使用
文章图片

从上面的代码中,我们设置了TextView1向下移动一次,背景颜色无限循环改变,点击start anim按钮,tv1启动动画,向下移动后回到原点,背景色做无限循环变色,然后我们点击cancel anim 按钮,打印出来的log如上图,只是打印了开始,退出,结束动画,并没有打印onAnimationRepeat()函数,得出结论:
(1)AnimatorSet设置的监听函数也是仅仅监听AnimatorSet的状态,与动画无关。
(2)AnimatorSet中没有设置循环次数的方法,所以AnimatorSet设置的监听方法永远运行不到onAnimationRepeat()中。
5、其他函数单个设置的区别
/** * 设置动画目标控件 */ void setTarget(Object target)() /** * 设置动画时间 */ AnimatorSet setDuration(long duration) /** * 设置插值器 */ void setInterpolator(TimeInterpolator interpolator)

其中AnimatorSet与单个控件拥有函数由一部分是相同的,如果同时使用他们会不会冲突呢?我们来校验一下他们的使用区别:
ObjectAnimator translation1 = ObjectAnimator.ofFloat(mTextView1, "translationY", 0f, 400f, 0f); translation1.setDuration(5000); translation1.setInterpolator(new BounceInterpolator()); ObjectAnimator rotation2 = ObjectAnimator.ofFloat(mTextView2, "rotation", 0f, 360f, 0f); rotation2.setDuration(10000); rotation2.setInterpolator(new AccelerateInterpolator()); //构建AnimatorSet实例 AnimatorSet animatorSet = new AnimatorSet(); animatorSet.play(translation1).with(rotation2); //设置动画时长 animatorSet.setDuration(1000); animatorSet.setTarget(mTextView1); animatorSet.setInterpolator(new LinearInterpolator()); //开启动画 animatorSet.start();

从上面的代码中,我们设置了mTextView1在5秒完成动画,向下移动400后再回到原点,插值器为BounceInterpolator;mTextView2在10秒内完成动画,旋转360度,再回到0度,插值器为AccelerateInterpolator。动画集合animatorSet设置了1秒,目标控件为mTextView1,插值器为LinearInterpolator,效果如下:
Android动画篇(六)—— 组合动画AnimatorSet和PropertyValuesHolder的使用
文章图片

从动画中可以看出,只有mTextView1做了动画,一秒内向下移动并且旋转然后回到原点,那么说明AnimatorSet中设置的会覆盖单个动画中设置的函数,我们再来看看AnimatorSet没有设置的时候是什么效果:
ObjectAnimator translation1 = ObjectAnimator.ofFloat(mTextView1, "translationY", 0f, 400f, 0f); translation1.setDuration(5000); translation1.setInterpolator(new BounceInterpolator()); ObjectAnimator rotation2 = ObjectAnimator.ofFloat(mTextView2, "rotation", 0f, 360f, 0f); rotation2.setDuration(10000); rotation2.setInterpolator(new AccelerateInterpolator()); //构建AnimatorSet实例 AnimatorSet animatorSet = new AnimatorSet(); animatorSet.play(translation1).with(rotation2); //开启动画 animatorSet.start();

效果如下:
Android动画篇(六)—— 组合动画AnimatorSet和PropertyValuesHolder的使用
文章图片

可以看出AnimatorSet没有设置的话则以单个动画中设置的为准。得出结论:
AnimatorSet设置以后会覆盖单个动画的设置,单个动画的设置变为无效;如果AnimatorSet没有设置则以单个动画的设置为准。
三、高级用法(PropertyValuesHolder的使用) ValueAnimator和ObjectAnimator除了通过ofInt()、ofFloat()、ofObject()还可以通过PropertyValuesHolder来创建实例,由于ValueAnimator用的比较少,这里使用ObjectAnimator来配合PropertyValuesHolder使用,来看看PropertyValuesHolder的构造方法:
//ValueAnimator ValueAnimator ofPropertyValuesHolder(PropertyValuesHolder... values) //ObjectAnimator ObjectAnimator ofPropertyValuesHolder(Object target,PropertyValuesHolder... values)

  • Object target指定执行动画的控件
  • PropertyValuesHolder... values可变长参数,可以传入多个PropertyValuesHolder实例,每一个实例都会针对控件做动画,多个实例会对控件同时做多个动画
PropertyValuesHolder的意义就是保存动画过程中所需要的属性和值,其实ofInt()和ofFloat()的内部实现就是通过封装PropertyValuesHolder实例来保存动画状态的,后面的操作也是以PropertyValuesHolder为主。
我们来看看创建PropertyValuesHolder实例的函数:
public static PropertyValuesHolder ofInt(String propertyName, int... values) public static PropertyValuesHolder ofFloat(String propertyName, float... values)

  • propertyName需要操作的属性名,通过反射需要找到的属性方法名
  • values属性所对应的参数,可变长参数
有不理解的同学可以参考《Android动画篇(五)—— 属性动画ObjectAnimator基本使用》
//创建PropertyValuesHolder实例 PropertyValuesHolder valuesHolder1 = PropertyValuesHolder.ofInt("backgroundColor", 0xffff00ff, 0xffffff00, 0xff0000ff); valuesHolder1.setEvaluator(new ArgbEvaluator()); PropertyValuesHolder valuesHolder2 = PropertyValuesHolder.ofFloat("scaleX", 0f, 2f, 0f, 3f, 1f); PropertyValuesHolder valuesHolder3 = PropertyValuesHolder.ofFloat("scaleY", 0f, 2f, 0f, 3f, 1f); //将创建PropertyValuesHolder实例添加到ObjectAnimator中 ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(mTextView1, valuesHolder1, valuesHolder2, valuesHolder3); objectAnimator.setDuration(2000); objectAnimator.start();

创建PropertyValuesHolder实例后,将实例分别添加到ObjectAnimator中,执行动画
效果如下:
Android动画篇(六)—— 组合动画AnimatorSet和PropertyValuesHolder的使用
文章图片

好了,有关动画集合的就这里结束了,有需要的朋友可以回头看看我前面写的几篇动画文章!
源码下载地址:https://github.com/FollowExcellence/AndroidAnimation
请大家尊重原创者版权,转载请标明出处: https://blog.csdn.net/m0_37796683/article/details/90645047 谢谢!
动画系列文章:
1、 Android动画篇(一)—— alpha、scale、translate、rotate、set的xml属性及用法
  • 补间动画的XML用法以及属性详解
2、Android动画篇(二)—— 代码实现alpha、scale、translate、rotate、set及插值器动画
  • 代码动态实现补间动画以及属性详解
3、 Android动画篇(三)—— 属性动画ValueAnimator的使用
  • ValueAnimator的基本使用
4、 Android动画篇(四)—— 属性动画ValueAnimator的高级进阶
  • 插值器(Interpolator)、计算器(Evaluator)、ValueAnimator的ofObject用法等相关知识
5、 Android动画篇(五)—— 属性动画ObjectAnimator基本使用
  • ObjectAnomator的基本使用以及属性详解
6、 Android动画篇(六)—— 组合动画AnimatorSet和PropertyValuesHolder的使用
  • AnimatorSet动画集合和PropertyValuesHolder的使用
以上几篇动画文章是一定要掌握的,写的不好请多多指出!

    推荐阅读