本章就专门介绍一下Android中的动画组合之一AnimationSet的介绍。
动画组合的四种方式
一般来说,Android实现动画组合有四种方式,分别是:
-
AnimationSet
-
AnimatorSet
-
PropertyValuesHolder
-
ViewPropertyAnimator
个人来说我用到的基本就前两种,所以也主要就介绍一下前两种。前两种的名称差不多,其实也是有其不同之处,这里简单介绍一下两个的不同点。
AnimationSet的使用
一般来我说我们在App中常用的都是一些视图动画:包括透明动画(AlphaAnimation)、旋转动画(RotateAnimation)、移动动画(TranslateAnimation)和缩放动画(ScaleAnimation),我们用AnimationSet就可以把这些动画组合起来实现我们想要的效果。
一般来我说我们在App中常用的都是一些视图动画:包括透明动画(AlphaAnimation)、旋转动画(RotateAnimation)、移动动画(TranslateAnimation)和缩放动画(ScaleAnimation),我们用AnimationSet就可以把这些动画组合起来实现我们想要的效果。
我们通过定义上面那四种动画组合,再使用animationSet.addAnimation的函数把动画加进来即可实现该效果。下面是列出来AnimationSet的几个比较常用的函数方法:
函数名 | 参数 | 说明 |
---|---|---|
构造函数 | boolean interpolator |
true:代表使用默认的interpolator false:代表使用自定义interpolator |
addAnimation | Animation a | 添加定义好的动画效果 |
setDuration | long time | 设置播放时长(毫秒) |
setRepeatCount | int count | 设置重放次数 |
setRepeatMode | int repeatmode | 设置重放模式 |
setInterpolator | interpolator i | 设置插值器 |
setFillAfter | boolean b | 是否保持动画完成后的位置 |
setFillBefore | boolean b | 是否保持动画开始时的状态 |
cancel | 无 | 取消AnimationSet |
reset | 无 | 释放AnimationSet |
上面的函数中setRepeatCount和setRepeatMode两个函数我用别的颜色标注了,主要是因为在使用的过程中发现不起作用,后来在网上找了找资料后发现在AnimationSet使用这个没有效果,需要在对应的Animaion的动画里面设置才行。
代码实现
我们在还是用上一章中那个Demo,新建一个AnimationScale的函数
private void AnimationScale() {
//构造方法的入参如果是“true”,则代表使用默认的interpolator,如果是“false”则代表使用自定义interpolator
AnimationSet animationSet=new AnimationSet(false);
//透明度从0至1
AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
//旋转两圈
RotateAnimation rotateAnimation=new RotateAnimation(0, 720, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
//放大十倍
ScaleAnimation scaleAnimation = new ScaleAnimation(1f, 10, 1f, 10, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation.setRepeatCount(1);
scaleAnimation.setRepeatMode(Animation.REVERSE);
//平移距离x方向为父控件宽的30.5%,y方向为父控件高的30.5%
TranslateAnimation translateAnimation=new TranslateAnimation(Animation.ABSOLUTE, 0, Animation.RELATIVE_TO_PARENT, 0.305f, Animation.ABSOLUTE, 0, Animation.RELATIVE_TO_PARENT, 0.305f);
translateAnimation.setRepeatCount(1);
translateAnimation.setRepeatMode(Animation.REVERSE);
animationSet.addAnimation(alphaAnimation);
animationSet.addAnimation(rotateAnimation);
animationSet.addAnimation(scaleAnimation);
animationSet.addAnimation(translateAnimation);
//设置动画时长为1秒
animationSet.setDuration(2000);
animationSet.setRepeatMode(AnimationSet.REVERSE);
//设置插值器为先加速再减速
animationSet.setInterpolator(new AccelerateDecelerateInterpolator());
//动画完成后保持位置
animationSet.setFillAfter(false);
//保持动画开始时的状态
animationSet.setFillBefore(true);
//取消动画
animationSet.cancel();
//释放资源
animationSet.reset();
//开始动画
tvshow.startAnimation(animationSet);
}
然后在btntest2的按钮下加入点击事件调用刚才创建的函数
运行起来的效果如图
上面我们已介绍了AnimationSet的组合动画,也简单说了一下AnimationSet与AnijmatorSet的区别,这一篇我们就要说试一试AnimatorSet的效果。
-
看了ValueAnimator和ObjectAnimator,他们只能实现一个动画,如果我们想使用一个组合动画,就需要用到AnimatorSet
-
一般而言我们不会使用ValueAnimator,只会使用ObjectAnimator组合动画实现
-
在AnimatorSet中提供了两个函数:playSequentially()和playTogether(),前者表示所用动画依次播放,后者表示动画一起播放
-
playSequentially()函数:
public void playSequentially(Animator... items);
public void playSequentially(List<Animator> items);
eg:
private void doAnimator() {
ObjectAnimator objectAnimator1 = ObjectAnimator.ofInt(textView1,"BackgroundColor", 0xffff00ff, 0xffffff00,0xffff00ff);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(textView1,"translationY",0 , 300, 0);
ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(textView2, "translationY", 0, 400, 0);
AnimatorSet animatorSet = new AnimatorSet();
//依次执行
animatorSet.playSequentially(objectAnimator1,objectAnimator2,objectAnimator3);
animatorSet.setDuration(1000);
animatorSet.start();
}
- playTogether()函数:
public void playTogether(Animator... items);
public void playTogether(Collection<Animator> items);
eg;
private void doAnimator() {
ObjectAnimator objectAnimator1 = ObjectAnimator.ofInt(textView1,"BackgroundColor", 0xffff00ff, 0xffffff00,0xffff00ff);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(textView1,"translationY",0 , 300, 0);
ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(textView2, "translationY", 0, 400, 0);
AnimatorSet animatorSet = new AnimatorSet();
//一起执行
animatorSet.playTogether(objectAnimator1, objectAnimator2, objectAnimator3);
animatorSet.setDuration(1000);
animatorSet.start();
}
- 两者比较:
- playTogether函数指的是在同一时间点,至于动画是否结束,以及何时结束都不管。
- playSequentially函数当执行一个动画的时候,必须等待该动画执行完毕才会执行下一个动画
- 通过下面的例子进行更详细的了解,在中间的控件上设置一个无线循环播放
- playTogether()效果是等到颜色变换后两个TextView做平移变换,变换后中间的控件还继续进行无限循环播放
private void doAnimator() {
ObjectAnimator objectAnimator1 = ObjectAnimator.ofInt(textView1,"BackgroundColor", 0xffff00ff, 0xffffff00,0xffff00ff);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(textView1,"translationY",0 , 300, 0);
//延时2秒,循环无穷次
objectAnimator2.setStartDelay(2000);
objectAnimator2.setRepeatCount(ValueAnimator.INFINITE);
ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(textView2, "translationY", 0, 400, 0);
objectAnimator3.setStartDelay(2000);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(objectAnimator1, objectAnimator2, objectAnimator3);
animatorSet.setDuration(2000);
animatorSet.start();
}
- playSequentially()效果是,第三个动画永远无法播放,因为中间的无限循环,所以第三个一直被阻塞
private void doAnimator() {
ObjectAnimator objectAnimator1 = ObjectAnimator.ofInt(textView1,"BackgroundColor", 0xffff00ff, 0xffffff00,0xffff00ff);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(textView1,"translationY",0 , 300, 0);
//延时2秒,循环无穷次
objectAnimator2.setStartDelay(2000);
objectAnimator2.setRepeatCount(ValueAnimator.INFINITE);
ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(textView2, "translationY", 0, 400, 0);
objectAnimator3.setStartDelay(2000);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playSequentially(objectAnimator1, objectAnimator2, objectAnimator3);
animatorSet.setDuration(2000);
animatorSet.start();
}
- AnimatorSet.Builder
- 为了解决无法自定义动画的播放顺序,Google提该类
//表示要播放哪一个动画
public Builder play(Animator anim);
//和前面的动画一起执行
public Builder with(Animator anim);
//先执行这个动画,再执行前面的动画
public Builder before(Animator anim);
//在执行前面的动画后才执行该动画
public Builder after(Animator anim);
//延迟n毫秒之后执行动画
public Builder after(long delay);
- before after等函数都是以当前播放的动画为基准
private void doAnimator() {
ObjectAnimator objectAnimator1 = ObjectAnimator.ofInt(textView1,"BackgroundColor", 0xffff00ff, 0xffffff00,0xffff00ff);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(textView1,"translationY",0 , 300, 0);
//延时2秒,循环无穷次
objectAnimator2.setStartDelay(2000);
objectAnimator2.setRepeatCount(ValueAnimator.INFINITE);
ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(textView2, "translationY", 0, 400, 0);
objectAnimator3.setStartDelay(2000);
AnimatorSet animatorSet = new AnimatorSet();
// animatorSet.playSequentially(objectAnimator1, objectAnimator2, objectAnimator3);
// animatorSet.setDuration(2000);
// animatorSet.start();
AnimatorSet.Builder builder = animatorSet.play(objectAnimator1);
builder.with(objectAnimator2);
//在执行完obj3之后在执行上面的动画
builder.after(objectAnimator3);
animatorSet.setDuration(1000);
animatorSet.start();
}
- Animator.Builder使用方法:
- 逐个添加(与上面的例子相同)
- 串行方式(生成器模式)
animatorSet.play(objectAnimator1).with(objectAnimator).after(objectAnimator3);
- AnimatorSet监听器:
public static interface AnimatorListener{
/**
* 当AnimatorSet开始调用
*/
void onAnimatorStart(Animator animator);
/**
* 当AnimatorSet结束时调用
*/
void onAnimationEnd(Animator animator);
/**
* 当AnimatorSet取消时调用
*/
void onAnimationCancel(Animator animator);
/**
* 当AnimatorSet重复时调用
*/
void onAnimationRepeat(Animator animator);
}
- 使用方式:
animatorSet.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
System.out.println("start");
}
@Override
public void onAnimationEnd(Animator animation) {
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
-
注意:AnimatorSet的监听函数只用来监听AnimatorSet的状态,与其中的动画无关,并且就算里面有重复的动画,他也永远无法执行onAnimationRepeat()函数
-
常用函数:
- 在AnimatorSet中还有如下几个函数:
//设置单次动画时长
public AnimatorSet setDuration(long duration);
//设置插值器
public void setInterpolator(TimeInterpolator interpolator);
//设置ObjectAnimator动画目标控件,只要通过该函数设置目标控件,那么单个动画中的目标控件都是以AnimatorSet为准
public void setTarget(Object target)
- 上述的函数在ObjectAnimator中也存在,但是如果在AnimatorSet中设置之后,会覆盖单个ObjectAnimator中的设置
- 例外的一个函数是setStartDelay(long startDelay)函数,它是用来设置AnimatorSet的激活时间的延时,单个动画的延时仍然有效。
- 注意
- AnimatorSet的真正的延时时间是本身设置的延时时间加上第一个单个动画的延时时间。
- AnimatorSet被激活后第一个动画肯定被执行,但是第二个动画可以根据自己的延时进行处理。
- 注意
Android动画之AnimatorSet组合动画
在ObjectAnimator中,因为需要设置属性,比如在scale中,可以使View在X轴或者Y轴缩放,但是如果想要使在X轴和Y轴同时缩放,就需要用到AnimatorSet。 在AnimatorSet中,提供了两个函数,分别是playSequentially和playTogether。前者表示所有的动画依次执行,后者表示所有的动画同时执行。
必须想要两个动画依次执行:
val objectAnimator1:ObjectAnimator = ObjectAnimator.ofFloat(textview,"alpha",1f,0f,1f)
val objectAnimator = ObjectAnimator.ofFloat(textview,"scaleX",1f,4f,1f)
AnimatorSet().apply {
duration = 2000
playSequentially(objectAnimator1,objectAnimator)
}.start()
同时执行:
val objectAnimator1:ObjectAnimator = ObjectAnimator.ofFloat(textview,"alpha",1f,0f,1f)
val objectAnimator = ObjectAnimator.ofFloat(textview,"scaleX",1f,4f,1f)
AnimatorSet().apply {
duration = 2000
playTogether(objectAnimator1,objectAnimator)
}.start()
总结: playSequentially和palyTogether函数在开始动画时,只负责把每个控件的动画激活,至于控件自身的动画是否超时,是否无限循环,只与控件自身的动画设定有关,这两个函数只负责到时间后激活动画。
如果我们想实现这样一组动画,有三个动画A、B、C,我们想先播放A,然后同时播放B和C,用以上的两个函数就无法实现,此时我们就需要用到AnimatorSet.Builder。
一下代码可实现以上的要求,先让View做渐隐渐现动画,然后同时进行旋转以及缩放动画。
val objectAnimator1:ObjectAnimator = ObjectAnimator.ofFloat(textview,"alpha",1f,0f,1f)
val objectAnimator2:ObjectAnimator = ObjectAnimator.ofFloat(textview,"rotation",0f,180f,360f)
val objectAnimator3:ObjectAnimator = ObjectAnimator.ofFloat(textview,"scaleX",1f,4f,1f)
val animatorSet = AnimatorSet()
animatorSet.play(objectAnimator1).apply {
before(objectAnimator2)
before(objectAnimator3)
}
animatorSet.duration = 2000
animatorSet.start()
以下是AnimatorsSet.Builder中的一些方法:
- play 表示播放哪个动画
- with 表示和前面的动画一起执行
- before 表示在播放before中指定的动画之前先播放play中的动画
- after 表示先播放after中的动画,再播放play中指定的动画。
方法 |
描述 |
---|---|
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毫秒之后执行动画 |
代码演示
private void AnimatorArray() {
//设置动画一往X轴方向从2缩放到10
ObjectAnimator animator1=ObjectAnimator.ofFloat(tvshow, "scaleX", 2, 10);
//设置动画二往Y轴方向从2缩放到10
ObjectAnimator animator2=ObjectAnimator.ofFloat(tvshow, "scaleY", 2, 10);
//设置动画三往X轴平移100再返回
ObjectAnimator animator3=ObjectAnimator.ofFloat(tvshow, "translationX", 0, 100, 0);
//设置动画四往Y轴平移100再返回
ObjectAnimator animator4=ObjectAnimator.ofFloat(tvshow, "translationY", 0, 100, 0);
AnimatorSet set=new AnimatorSet();
//设置动画的基础属性
set.play(animator1).with(animator2).after(animator3).before(animator4);
set.setDuration(1000);//播放时长
set.setStartDelay(100);//延迟播放
set.setInterpolator(new AccelerateDecelerateInterpolator());
set.start();
}
上面代码我们在原来的基础又加了两个动画,动画三是向左平移100再返回,动画四是向下平移100再返回。
上图中的设置属性说明先执行animator3(向左平移再返回),再同时执行animator1和animator2(横向及纵向同时放大),最后再执行animator4(向下平移再返回),接下来我们看看效果