前言:把握生命里的每一分钟,全力以赴心中的梦。不经历风雨,怎么见彩虹,没有人能随随便便成功。----《真心英雄》一、概述 我们在上一篇文章中已经详细讲解了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();
效果如下:
文章图片
从图中可以看出,我们设置了两个动画,一个颜色渐变,一个向下移动,调用playTogether()函数后,两个动画都同时启动了。
2、playTogether和playSequentially
(1)playTogether
- playTogether(Animator... items)同时开启动画,参数是可变长参数,参数为需要执行的动画
- playTogether(Collection items)同时开启动画,参数是动画合集
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();
效果图如下:
文章图片
从图中可以看出,开启动画的时候,三个动画时同时执行的,tv1的背景颜色变化和位移以及tv2的位移都是同时开始。
(2)playSequentially
- playSequentially(Animator... items)逐个播放动画,可变长参数,参数为需要执行的动画
- playSequentially(List items)逐个播放动画,参数为需要执行的动画的集合
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();
效果如下:
文章图片
从上面的效果可以看到,动画时一个执行完以后再执行下一个动画,动画合集里面我们是一个个添加进去的,即先加入颜色变化动画,再加入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();
效果:
文章图片
从上面看到,三个动画已经通过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();
效果如下:
文章图片
从效果图可以看出,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按钮结束动画,效果如下:
文章图片
文章图片
从上面的代码中,我们设置了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,效果如下:
文章图片
从动画中可以看出,只有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();
效果如下:
文章图片
可以看出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实例的函数:
public static PropertyValuesHolder ofInt(String propertyName, int... values)
public static PropertyValuesHolder ofFloat(String propertyName, float... values)
- propertyName需要操作的属性名,通过反射需要找到的属性方法名
- values属性所对应的参数,可变长参数
//创建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中,执行动画
效果如下:
文章图片
好了,有关动画集合的就这里结束了,有需要的朋友可以回头看看我前面写的几篇动画文章!
源码下载地址:https://github.com/FollowExcellence/AndroidAnimation
请大家尊重原创者版权,转载请标明出处: https://blog.csdn.net/m0_37796683/article/details/90645047 谢谢!
动画系列文章:
1、 Android动画篇(一)—— alpha、scale、translate、rotate、set的xml属性及用法
2、Android动画篇(二)—— 代码实现alpha、scale、translate、rotate、set及插值器动画
- 补间动画的XML用法以及属性详解
3、 Android动画篇(三)—— 属性动画ValueAnimator的使用
- 代码动态实现补间动画以及属性详解
4、 Android动画篇(四)—— 属性动画ValueAnimator的高级进阶
- ValueAnimator的基本使用
5、 Android动画篇(五)—— 属性动画ObjectAnimator基本使用
- 插值器(Interpolator)、计算器(Evaluator)、ValueAnimator的ofObject用法等相关知识
6、 Android动画篇(六)—— 组合动画AnimatorSet和PropertyValuesHolder的使用
- ObjectAnomator的基本使用以及属性详解
以上几篇动画文章是一定要掌握的,写的不好请多多指出!
- AnimatorSet动画集合和PropertyValuesHolder的使用
推荐阅读
- android动画系列|Android动画之AnimatorSet联合动画用法
- android动画系列|Android动画之ValueAnimator用法和自定义估值器
- android动画系列|Android动画之ObjectAnimator中ofXX函数全解析-自定义Property,TypeConverter,TypeEvaluator
- Android动画篇(三)—— 属性动画ValueAnimator的使用
- Android动画系列|Android动画篇(五)—— 属性动画ObjectAnimator基本使用
- Android动画系列|Android动画篇(二)—— 代码实现alpha、scale、translate、rotate、set及插值器动画
- 动画七、动画的PropertyValuesHolder与Keyframe
- Android动画篇(四)—— 属性动画ValueAnimator的高级进阶