动画八、联合动画的实现

本学习笔记主要来自启舰:
http://blog.csdn.net/harvic880925/article/details/50759059
在学习过程中融入了自己的理解和思路。

在实际使用中,都是使用ObjectAnimator的机率比较大。
但ValueAnimator和ObjectAnimator都只能单单实现一个动画,如果我们想要使用一个组合动画,比如边放大,边移动,边改变alpha值,ValueAnimator和ObjectAnimator动画距明显解决不了问题。对于这种组合型的动画,谷歌给我们提供了一个类AnimatorSet;这篇我们就着重来看看组合动画的实现方法吧。

一、AnimatorSet——playSequentially,playTogether
首先,AnimatorSet针对ValueAnimator和ObjectAnimator都是适用的,但一般而言,我们不会用到ValueAnimator的组合动画,所以我们这篇仅讲解ObjectAnimator下的组合动画实现。

在AnimatorSet中直接给为我们提供了两个方法playSequentially(按顺序)和playTogether(一起),playSequentially表示所有动画依次播放,playTogether表示所有动画一起开始。

1、playSequentially:将动画组装起来,逐个播放
我们先来看看playSequentially的声明:

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

第一个是我们最常用的,它的参数是可变长参数,也就是说我们可以传进去任意多个Animator对象。这些对象的动画会逐个播放。第二个构造方法,是传进去一个List< Animator>的列表。原理一样,也是逐个去取List中的动画对象,然后逐个播放。但使用起来稍微麻烦一些。

private void objAnimatorSequentially(){
    ObjectAnimator backGround01 = ObjectAnimator.ofInt(mTvAnimator01, 
		 "BackgroundColor", 0xffff0000, 0xff00ff00, 0xff0000ff);
    backGround01.setRepeatCount(1);
    ObjectAnimator backGround02 = ObjectAnimator.ofInt(mTvAnimator02, 
        "BackgroundColor", 0xff0000ff, 0xffff0000, 0xff00ff00);
    backGround02.setRepeatCount(1);
    ObjectAnimator translationY01 = ObjectAnimator.ofFloat(mTvAnimator01, 
        "translationY", 150, 280, 500,0);
    translationY01.setRepeatCount(1);
    ObjectAnimator translationY02 = ObjectAnimator.ofFloat(mTvAnimator02, 
        "translationY", 200, 320, 550,0);
    translationY02.setRepeatCount(1);
    animatorSet = new AnimatorSet();
    animatorSet.playSequentially(translationY02, 
        backGround01, translationY01, backGround02);
	//animatorSet.playTogether(translationY02, 
		backGround02, backGround01, translationY01);
    animatorSet.setDuration(4000);
    animatorSet.setInterpolator(new BounceInterpolator());
    animatorSet.start();
}

上面代码运行的时候,会发现:动画是按照playSequentially里面的添加顺序执行的。如果playSequentially里面的添加顺序改成斜体下划线删除线的代码顺序,则会按照新的顺序执行。这正印证了playSequentially的含义:按顺序。
利用AnimatorSet的playSequentially方法将这三个动画组装起来,逐个播放。代码很好理解,不再细讲。

2、playTogether:
playTogether表示将所有动画一起播放 。
我们先来看看playTogether的声明:

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

用法示例:将上面1中有灰色底纹背景的代码改成下面一行代码,其他一切不变:

animatorSet.playTogether(translationY02, backGround02, backGround01, translationY01);

同样是上面的那四个动画,只是将playSequentially改为了playTogether;见加粗部分字体。执行过程中,会发现,无论怎么调整playTogether中动画的顺序,他们都会同时执行,正印证了playTogether的含义:同时,一起。

3、playSequentially,playTogether真正意义
playTogether和playSequentially在开始动画时,只是把每个控件的动画激活,至于每个控件自身的动画是否具有延时、是否无限循环,只与控件自身的动画设定有关,与playTogether、playSequentially无关。playTogether和playSequentially只负责到点激活动画。

总结:
第一:playTogetherplaySequentially在激活动画后,控件的动画情况与它们无关,他们只负责定时激活控件动画。
第二:playSequentially只有控件的上一个动画做完以后,才会激活控件的下一个动画,如果控件的上一动画是无限循环,那控件的下一个动画甚至下一个控件的动画就别再指望了。

4、如何实现无限循环动画
是否无限循环主要是看动画本身,与playSequentially/playTogether无关!(这句话有bug。这个分两个情况来解释,一是playTogether:在playTogether情况下,每个控件的所有动画是同时执行的,没有先后顺序之分,所以是否无限循环主要是看动画本身,与playTogether无关;二是playSequentially在执行顺序上,见上面总结的第二条):

private void objAnimatorSequentially(){
    ObjectAnimator backGround01 = ObjectAnimator.ofInt(mTvAnimator01, 
        "BackgroundColor", 0xffff0000, 0xff00ff00, 0xff0000ff);
    backGround01.setRepeatCount(ValueAnimator.INFINITE);
    ObjectAnimator backGround02 = ObjectAnimator.ofInt(mTvAnimator02, 
        "BackgroundColor", 0xff0000ff, 0xffff0000, 0xff00ff00);
    backGround02.setRepeatCount(ValueAnimator.INFINITE);
    ObjectAnimator translationY01 = ObjectAnimator.ofFloat(mTvAnimator01, 
        "translationY", 150, 280, 500,0);
    translationY01.setRepeatCount(ValueAnimator.INFINITE);
    ObjectAnimator translationY02 = ObjectAnimator.ofFloat(mTvAnimator02, 
        "translationY", 200, 320, 550,0);
    translationY02.setRepeatCount(ValueAnimator.INFINITE);
    animatorSet = new AnimatorSet();
    animatorSet.playTogether(translationY02, backGround02, 
        backGround01, translationY01);
    animatorSet.setDuration(2000);
    animatorSet.setInterpolator(new BounceInterpolator());
    animatorSet.start();
}

联合动画的无限循环,是通过ObjectAnimator的对象translationY01调用setRepeatCount()方法来设置的。AnimatorSet类并没有setRepeatCount()方法。

总之:

AnimatorSet没有setRepeatCount方法,只是通过playTogether和playSequentially负责指定什么时候开始动画,不干涉动画自己的运行过程。换言之:playTogether和playSequentially只是赛马场上的每个赛道的门,门打开以后,赛道上的那匹马怎么跑跟它没什么关系。

二、自由设置动画顺序——AnimatorSet.Builder

1、概述
我们讲了playTogether和playSequentially,分别能实现一起开始动画和逐个开始动画。但并不是非常自由的组合动画,比如我们有三个动画A,B,C我们想先播放C然后同时播放A和B。利用playTogether和playSequentially是没办法实现的,所以为了更方便的组合动画,谷歌的开发人员另外给我们提供一个类AnimatorSet.Builder;

private void objAnimatorBuilder(){
	ObjectAnimator backGround01 = ObjectAnimator.ofInt(mTvAnimator01, 
		"BackgroundColor", 0xffff0000, 0xff00ff00, 0xff0000ff);
	backGround01.setRepeatCount(1);
	ObjectAnimator backGround02 = ObjectAnimator.ofInt(mTvAnimator02, 
		"BackgroundColor", 0xff0000ff, 0xffff0000, 0xff00ff00);
	backGround02.setRepeatCount(1);
	ObjectAnimator translationY01 = ObjectAnimator.ofFloat(mTvAnimator01, 
		"translationY", 150, 280, 500,0);
	translationY01.setRepeatCount(1);
	ObjectAnimator translationY02 = ObjectAnimator.ofFloat(mTvAnimator02, 
		"translationY", 200, 320, 550,0);
	translationY02.setRepeatCount(1);
	mAnimatorset = new AnimatorSet();
	AnimatorSet.Builder mBuilder = mAnimatorset.play(backGround01).with(translationY01)
		.after(backGround02).before(translationY02);
	mAnimatorset.setDuration(3000);
	mAnimatorset.setTarget(mTvAnimator02);
	mAnimatorset.start();
}

首先是构造一个AnimatorSet对象。然后调用animatorSet.play(backGround01)方法生成一个AnimatorSet.Builder对象并加入要先播放的动画backGround01,再调用builder.with()添加第二个要播放的动画translationY01,就实现了两个控件同时做动画了,多么神奇。

2、AnimatorSet.Builder方法含义详解

从上面的代码中,我们可以看到AnimatorSet.Builder是通过animatorSet.play(backGround01)生成的,这是生成AnimatorSet.Builder对象的唯一途径!
//调用AnimatorSet中的play方法是获取AnimatorSet.Builder对象的唯一途径

//表示要播放哪个动画
public Builder play(Animator anim)
//和前面动画一起执行
public Builder with(Animator anim)
//执行前面的动画后才执行该动画
public Builder before(Animator anim)
//先执行after方法里面的动画再执行前面动画
public Builder after(Animator anim)
//延迟n毫秒之后执行动画
public Builder after(long delay)

如下:

private void objAnimatorBuilder(){
	ObjectAnimator backGround01 = ObjectAnimator.ofInt(mTvAnimator01, 
		"BackgroundColor", 0xffff0000, 0xff00ff00, 0xff0000ff);
	backGround01.setRepeatCount(1);
	ObjectAnimator backGround02 = ObjectAnimator.ofInt(mTvAnimator02, 
		"BackgroundColor", 0xff0000ff, 0xffff0000, 0xff00ff00);
	backGround02.setRepeatCount(1);
	ObjectAnimator translationY01 = ObjectAnimator.ofFloat(mTvAnimator01, 
			"translationY", 150, 280, 500,0);
	translationY01.setRepeatCount(1);
	ObjectAnimator translationY02 = ObjectAnimator.ofFloat(mTvAnimator02, 
			"translationY", 200, 320, 550,0);
	translationY02.setRepeatCount(1);	
	mAnimatorset = new AnimatorSet();
	AnimatorSet.Builder mBuilder1 = mAnimatorset.play(backGround01);
	mBuilder1.with(translationY01);
	mBuilder1.after(backGround02);//after括号里面的动画先执行。
	mBuilder1.before(translationY02);
	mAnimatorset.setDuration(3000);
	mAnimatorset.setTarget(mTvAnimator02);
	mAnimatorset.start();
}

上面动画执行顺序是:先执行backGround02,然后translationY01和backGround01同时执行,最后再是translationY02;这里的执行顺序与after、before代码的先后顺序无关,只跟里面的动画对象有关。

由于每个方法的返回值都是Builder对象,所以我们是依然可以直接调用Builder的所有方法的,所以就可以用串行的方式把他们一行串起来,所以上面的代码我们也可以写成下面的简化方式:

AnimatorSet.Builder mBuilder = mAnimatorset
		.play(backGround01).with(translationY01)
		.after(backGround02).before(backGround01);

三、AnimatorSet监听器

在AnimatorSet中也可以添加监听器,对应的监听器为:

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);
}

添加方法为:

//这与前面给ValueAnimator添加监听是一致的。
public void addListener(AnimatorListener listener);

AnimatorSet的监听总结:

1、AnimatorSet的监听方法也只是用来监听AnimatorSet的状态的,与其中的动画无关;
2、AnimatorSet中没有设置循环的方法,所以AnimatorSet监听器中永远无法运行到onAnimationRepeat()中!
3、有关如何实现无限循环的问题,解决方式是给每个动画独立设置onAnimationRepeat();

四、通用方法逐个设置与AnimatorSet设置的区别

1、概述及示例
在AnimatorSet中还有几个方法:

//设置单次动画时长
public AnimatorSet setDuration(long duration); 
//设置加速器
public void setInterpolator(TimeInterpolator interpolator) ;
//设置ObjectAnimator动画目标控件
public void setTarget(Object target) ;

在ObjectAnimator中也都有这几个方法。那在AnimatorSet中设置与在单个ObjectAnimator中设置有什么区别呢?

————区别就是: 如果AnimatorSet中没有设置,那么就以ObjectAnimator中的设置为准。如果AnimatorSet中设置以后,ObjectAnimator中的设置就会无效,即: 在AnimatorSet中设置以后,会覆盖单个ObjectAnimator中的设置。

2、setTarget(Object target):
只要通过AnimatorSet的setTartget方法设置了目标控件,那么单个动画中的目标控件都以AnimatorSet设置的为准 ;如前面的Builder顺序动画,我们给mTvAnimator01和mTvAnimator02设置了改变背景色和上下移动的动画。但由于我们通过mAnimatorset.setTarget(mTvAnimator02);将各个动画的目标控件设置为mTvAnimator02,所以mTvAnimator01将不会有任何动画,所有的动画都会发生在mTvAnimator02上。

五、AnimatorSet之setStartDelay(long startDelay)

//API提供的setStartDelay方法
//设置延时开始动画时长
public void setStartDelay(long startDelay) 

上面我们讲了,当AnimatorSet所拥有的方法与单个动画所拥有的方法冲突时,就以AnimatorSet设置为准。但唯一的例外就是setStartDelay。setStartDelay方法不会覆盖单个动画的延时,而且仅针对性的延长AnimatorSet的激活时间,单个动画的所设置的setStartDelay仍对单个动画起作用。

ObjectAnimator tv1TranslateY = ObjectAnimator.ofFloat(mTv1, 
			"translationY", 0, 400, 0);
ObjectAnimator tv2TranslateY = ObjectAnimator.ofFloat(mTv2, 
			"translationY", 0, 400, 0);
tv2TranslateY.setStartDelay(2000);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(tv1TranslateY).with(tv2TranslateY);
animatorSet.setStartDelay(2000);
animatorSet.setDuration(2000);
animatorSet.start();

在这个动画中,我们首先给AnimatorSet设置了延时,所以AnimatorSet会在2000毫秒以后,才会执行start()方法。另外我们还给tv2设置了延时2000毫秒,所以在动画开始后,mTv1会直接运动,但mTv2要等2000毫秒以后,才会开始运动。也就是mTv2一共被延时了4000ms的时间;
另外,AnimatorSet的延时是仅针对性的延长AnimatorSet激活时间的,对单个动画的延时设置没有影响。

注意:注意::注意:::
上面的动画顺序:

animatorSet.play(tv1TranslateY).with(tv2TranslateY);

这里将动画顺序调换一下:

animatorSet.play(tv2TranslateY).with(tv1TranslateY);

看会是什么结果呢?
按说这里的效果应该与上个的效果是一样的才对,即在AnimatorSet被激活以后,mTv1应该立即运行,等2000毫秒后mTv2才开始运行。但这里的效果却是过了一段时间以后,mTv1和mTv2一起运行!
这是因为:AnimatorSet真正激活延时 = AnimatorSet.startDelay + 第一个动画.startDelay;也就是说AnimatorSet被激活的真正延时等于它本身设置的setStartDelay(2000)延时再加上第一个动画的延时;

结论:
1、AnimatorSet的延时是仅针对性的延长AnimatorSet激活时间的,对单个动画的延时设置没有影响。
2、AnimatorSet真正激活延时 = AnimatorSet.startDelay+第一个动画.startDelay
3、在AnimatorSet激活之后,第一个动画绝对是会开始运行的,后面的动画则根据自己是否延时自行处理。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值