前言:为了梦想,行色匆匆,是否会错过眼前的风景?有时也会懊悔,为何当时没能好好享受时光,但如果当时真的跟他人一样,是否现在也会跟他人一样羡慕现在的自己?
上几篇给大家分别讲了valueanimator和objectanimator,相比而言objectanimator更为方便而且由于set函数是在控件类内部实现,所以封装性更好。而且在现实使用中一般而言都是使用objectanimator的机率比较大。
但valueanimator和objectanimator都只能单单实现一个动画,那如果我们想要使用一个组合动画,比如边放大,边移动,边改变alpha值,要怎么办。对于这种组合型的动画,谷歌给我们提供了一个类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 items);
这里有两种声明,第一个是我们最常用的,它的参数是可变长参数,也就是说我们可以传进去任意多个animator对象。这些对象的动画会逐个播放。第二个构造函数,是传进去一个list的列表。原理一样,也是逐个去取list中的动画对象,然后逐个播放。但使用起来稍微麻烦一些。
下面我们就举例来看一下playsequentially的使用方法,先来看下效果:
从效果图中可以看到,首先改变了textview1的颜色,结束后移动textview1,在移动结束后,开始移动黄色的textview;所以这就是playsequentially的效果,即逐个播放动画,一个动画结束后,播放下一个动画
下面我们来看实现代码:
(1)、main.xml布局 从效果图中也可以看出布局非常简单,就三个控件。代码如下:
这里也没有什么需要注意的地方,下面我们就直接来看myactivity的代码:
(2)、myactivity.java public class myactivity extends activity { private button mbutton; private textview mtv1, mtv2; @override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); mbutton = (button) findviewbyid(r.id.btn); mtv1 = (textview) findviewbyid(r.id.tv_1); mtv2 = (textview) findviewbyid(r.id.tv_2); mbutton.setonclicklistener(new view.onclicklistener() { @override public void onclick(view v) { doplaysequentiallyanimator(); } }); } …………}
这段代码也没什么难度,首先是初始化textview1,textview2和btn的对象,然后当点击按钮时执行doplaysequentiallyanimator();函数。下面我们来看看doplaysequentiallyanimator()的具体实现:
private void doplaysequentiallyanimator(){ objectanimator tv1bganimator = objectanimator.ofint(mtv1, backgroundcolor, 0xffff00ff, 0xffffff00, 0xffff00ff); objectanimator tv1translatey = objectanimator.offloat(mtv1, translationy, 0, 300, 0); objectanimator tv2translatey = objectanimator.offloat(mtv2, translationy, 0, 400, 0); animatorset animatorset = new animatorset(); animatorset.playsequentially(tv1bganimator,tv1translatey,tv2translatey); animatorset.setduration(1000); animatorset.start();}
这里首先构造了三个动画,针对textview1的是前两个tv1bganimator和tv1translatey:分别是改变当前动画背景和改变控件y坐标位置;针对textview2则只是通过translationy来改变控件y坐标位置。有关动画的创建方式,我这里就不再讲了,不理解的同学请参考上篇《animation动画详解(七)——objectanimator基本使用》
然后是利用animatorset的playsequentially函数将这三个动画组装起来,逐个播放。代码比较简单,就不再细讲。这篇我们就会在这个demo的基础上来讲解本篇所有的知识点。
源码在文章底部给出
2、playtogether playtogether表示将所有动画一起播放
我们先来看看playtogether的声明:
public void playtogether(animator... items);public void playtogether(collection items);
同样这里也是有两个构造函数,他们两个的意义是一样的,只是传入的参数不一样,第一个依然是传可变长参数列表,第二个则是需要传一个组装好的collection对象。
下面我们在上面例子的基础上,看看playtogether函数的用法;
先来看看效果图:
从效果图中可以看到,所有动画是一起开始播放的,下面来看看代码:
当点击控钮时,执行以下代码:
objectanimator tv1bganimator = objectanimator.ofint(mtv1, backgroundcolor, 0xffff00ff, 0xffffff00, 0xffff00ff);objectanimator tv1translatey = objectanimator.offloat(mtv1, translationy, 0, 400, 0);objectanimator tv2translatey = objectanimator.offloat(mtv2, translationy, 0, 400, 0);animatorset animatorset = new animatorset();animatorset.playtogether(tv1bganimator,tv1translatey,tv2translatey);animatorset.setduration(1000);animatorset.start();
同样是上面的那三个动画,只是将playsequentially改为了playtogether;
源码在文章底部给出
3、playsequentially,playtogether真正意义 想必大家都看到赛马,在赛马开始前,每个马都会被放在起点的小门后面,到点了,门打开,马开始一起往前跑。而假如我们把每匹马看做是一个动画,那我们的playtogether就相当于赛马场里每个赛道上门的意义(当比赛开始时,每个赛道上的门会打开,马就可以开始比赛了);也就是说,playtogether只是一个时间点上的一起开始,对于开始后,各个动画怎么操作就是他们自己的事了,至于各个动画结不结束也是他们自已的事了。所以最恰当的描述就是门只负责打开,打开之后马咋跑,门也管不着,最后,马回不回来跟门也没啥关系。门的责任只是到点就打开而已。放在动画上,就是在激活动画之后,动画开始后的操作只是动画自己来负责。至于动画结不结束,也只有动画自己知道。
而playsequentially的意义就是当一匹马回来以后,再放另一匹。那如果上匹马永远没回来,那下一匹马也永远不会被放出来。放到动画上,就是把激活一个动画之后,动画之后的操作就是动画自己来负责了,这个动画结束之后,再激活下一个动画。如果上一个动画没有结束,那下一个动画就永远也不会被激活。
我们首先用playtogether来看个例子:
objectanimator tv1bganimator = objectanimator.ofint(mtv1, backgroundcolor, 0xffff00ff, 0xffffff00, 0xffff00ff);objectanimator tv1translatey = objectanimator.offloat(mtv1, translationy, 0, 400, 0);tv1translatey.setstartdelay(2000);tv1translatey.setrepeatcount(valueanimator.infinite);objectanimator tv2translatey = objectanimator.offloat(mtv2, translationy, 0, 400, 0);tv2translatey.setstartdelay(2000);animatorset animatorset = new animatorset();animatorset.playtogether(tv1bganimator,tv1translatey,tv2translatey);animatorset.setduration(2000);animatorset.start();
在这个例子中,我们将tv1translatey开始延迟2000毫秒开始,并设为无限循环。tv2translatey设为开始延迟2000毫秒。而tv1bganimator则是没有任何设置,所以是默认直接开始。我们来看效果图:
在效果图中可以看到,在点击按钮以后,先进行的是颜色变化,在颜色变化完以后,两个textview才开始位移变换。最后textview1的位移变换是无限循环的。
所以从这个例子中也可以看到,playtogether只是负责在同一时间点把门拉开,拉开门以后,马跑不跑,那是它自己的事了,回不回来,门也管不着。
playsequentially也是一样,只是一个回来结束以后,才打开另一个的门。如果上一个一直没回来,那下一个也是永远不会开始的。
通过这个例子,我想告诉大家:playtogether和playsequentially在开始动画时,只是把每个控件的动画激活,至于每个控件自身的动画是否具有延时、是否无限循环,只与控件自身的动画设定有关,与playtogether、playsequentially无关。playtogether和playsequentially只负责到点激活动画。
我们再来看一个例子:
objectanimator tv1bganimator = objectanimator.ofint(mtv1, backgroundcolor, 0xffff00ff, 0xffffff00, 0xffff00ff);tv1bganimator.setstartdelay(2000);objectanimator tv1translatey = objectanimator.offloat(mtv1, translationy, 0, 300, 0);tv1translatey.setrepeatcount(valueanimator.infinite);objectanimator tv2translatey = objectanimator.offloat(mtv2, translationy, 0, 400, 0);animatorset animatorset = new animatorset();animatorset.playsequentially(tv1bganimator,tv1translatey,tv2translatey);animatorset.setduration(2000);animatorset.start();
同样是那三个动画,首先tv1bganimator设置了延时开始,tv1translatey设置为无限循环;使用playsequentially来逐个播放这三个动画,首先是tv1bganimator:在开始之后,这个动画会延时2000毫秒再开始。结束之后,激活tv1translatey,这个动画会无限循环。无限循环也就是说它永远也不会结束。那么第三个动画tv2translatey也永远不会开始。下面来看看效果图:
在效果图中也可以看出,textview1先是等了一段时间然后开始背景色变化,然后开始无限循环的上下运动。另一个textview永远也不会开始动画了。
源码在文章底部给出
通过上面两个例子,总结的时候到了:
- 第一:playtogether和playsequentially在激活动画后,控件的动画情况与它们无关,他们只负责定时告诉控件要开始做动画了。
- 第二:playsequentially只有上一个控件做完动画以后,才会激活下一个控件的动画,如果上一控件的动画是无限循环,那下一个控件就别再指望能做动画了。
4、无何实现无限循环动画 很多同学会一直纠结如何实现无限循环的动画,因为animatorset中没有设置循环次数的函数!通过上面的讲解,我们也能知道是否无限循环主要是看动画本身,与门(playtogether)无关!
下面我们就实现三个动画同时开始并无限循环的动画:
objectanimator tv1bganimator = objectanimator.ofint(mtv1, backgroundcolor, 0xffff00ff, 0xffffff00, 0xffff00ff);tv1bganimator.setrepeatcount(valueanimator.infinite);objectanimator tv1translatey = objectanimator.offloat(mtv1, translationy, 0, 400, 0);tv1translatey.setrepeatcount(valueanimator.infinite);objectanimator tv2translatey = objectanimator.offloat(mtv2, translationy, 0, 400, 0);tv2translatey.setrepeatcount(valueanimator.infinite);animatorset animatorset = new animatorset();animatorset.playtogether(tv1bganimator,tv1translatey,tv2translatey);animatorset.setduration(2000);animatorset.start();
上面的代码很容易理解,我们为每个动画设置了无限循环,所以在playtogether指定开始动画之后,每个动画都是无限循环的。
效果图如下:
总之:playtogether和playsequentially只是负责指定什么时候开始动画,不干涉动画自己的运行过程。换言之:playtogether和playsequentially只是赛马场上的每个赛道的门,门打开以后,赛道上的那匹马怎么跑跟它没什么关系。
源码在文章底部给出
二、自由设置动画顺序——animatorset.builder 1、概述 上面我们讲了playtogether和playsequentially,分别能实现一起开始动画和逐个开始动画。但并不是非常自由的组合动画,比如我们有三个动画a,b,c我们想先播放c然后同时播放a和b。利用playtogether和playsequentially是没办法实现的,所以为了更方便的组合动画,谷歌的开发人员另外给我们提供一个类animatorset.builder;
我们这里使用animatorset.builder实现下面这个效果:
即两个控件一同开始动画
我们直接来看实现的代码:
objectanimator tv1bganimator = objectanimator.ofint(mtv1, backgroundcolor, 0xffff00ff, 0xffffff00, 0xffff00ff);objectanimator tv1translatey = objectanimator.offloat(mtv1, translationy, 0, 400, 0);animatorset animatorset = new animatorset();animatorset.builder builder = animatorset.play(tv1bganimator);builder.with(tv1translatey);animatorset.start();
关键部分在最后几句:
animatorset animatorset = new animatorset();animatorset.builder builder = animatorset.play(tv1bganimator);builder.with(tv1translatey);
首先是构造一个animatorset对象。然后调用animatorset.play(tv1bganimator)方法生成一个animatorset.builder对象,直接调用builder.with()就能实现两个控件同时做动画了,多么神奇,下面我们来看看这个animatorset.builder的定义!
源码在文章底部给出
2、animatorset.builder函数 从上面的代码中,我们可以看到animatorset.builder是通过animatorset.play(tv1bganimator)生成的,这是生成animatorset.builder对象的唯一途径!
//调用animatorset中的play方法是获取animatorset.builder对象的唯一途径//表示要播放哪个动画public builder play(animator anim)
在上面的例子中,我们已经接触animatorset.builder的with(animator anim)函数,其实除了with函数以外,animatorset.builder还有一些函数,声明如下:
//和前面动画一起执行public builder with(animator anim)//执行前面动画前执行动画public builder before(animator anim)//执行前面的动画后执行该动画public builder after(animator anim)//延迟n毫秒之后执行动画public builder after(long delay)
上面每个函数的意义很好理解,这里要格外注意一点,他们每个函数的返回值都是builder对象,也就是说我们有两种方式使用他们:
方式一:使用builder对象逐个添加动画 animatorset.builder builder = animatorset.play(tv1translatey);builder.with(tv2translatey);builder.after(tv1bganimator);
方式二:串行方式 由于每个函数的返回值都是builder对象,所以我们是依然可以直接调用builder的所有函数的,所以就可以用串行的方式把他们一行串起来,所以上面的代码我们也可以写成下面的简化方式:
animatorset.play(tv1translatey).with(tv2translatey).after(tv1bganimator);
下面我们就举个例子来看一下他们的用法:
objectanimator tv1bganimator = objectanimator.ofint(mtv1, backgroundcolor, 0xffff00ff, 0xffffff00, 0xffff00ff);objectanimator tv1translatey = objectanimator.offloat(mtv1, translationy, 0, 400, 0);objectanimator tv2translatey = objectanimator.offloat(mtv2, translationy, 0, 400, 0);animatorset animatorset = new animatorset();animatorset.play(tv1translatey).with(tv2translatey).after(tv1bganimator);animatorset.setduration(2000);animatorset.start();
上面的代码比较简单,就不再讲了,看下效果图:(这里实现的效果是:在tv1颜色变化后,两个控件一同开始位移动画)
源码在文章底部给出
三、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);}
添加方法为:
public void addlistener(animatorlistener listener);
好像这个listenner和valueanimator的一模一样啊。不错,确实是一模一样,因为valueanimator和animatorset都派生自animator类,而animatorlistener是animator类中的函数。
监听器的用法并不难,难点在于,我们animatorset中的监听器,监听的animatorset本身的动作,还是它内部的每个动画的动作?在animatorset代码注释中我们已经提到,它监听的是animatorset的过程,所以只有当animatorset的状态发生变化时,才会被调用。
我们来看个例子:
额外添加一个cancel按钮,在点击start按钮时,开始动画,在点击取消按钮时取消动画
private animatorset manimatorset;public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); mbutton = (button) findviewbyid(r.id.btn); mbtncancel = (button) findviewbyid(r.id.btn_cancel); mtv1 = (textview) findviewbyid(r.id.tv_1); mtv2 = (textview) findviewbyid(r.id.tv_2); mbutton.setonclicklistener(new view.onclicklistener() { @override public void onclick(view v) { manimatorset = dolisteneranimation(); } }); mbtncancel.setonclicklistener(new view.onclicklistener() { @override public void onclick(view v) { if (null != manimatorset) { manimatorset.cancel(); } } });}
这段代码很简单,在点击开始时,执行 dolisteneranimation()函数, dolisteneranimation()会把构造的animatorset对象返回,在点击取消时,取消animatorset;
然后看一下 dolisteneranimation()的代码:
private animatorset dolisteneranimation() { objectanimator tv1bganimator = objectanimator.ofint(mtv1, backgroundcolor, 0xffff00ff, 0xffffff00, 0xffff00ff); objectanimator tv1translatey = objectanimator.offloat(mtv1, translationy, 0, 400, 0); objectanimator tv2translatey = objectanimator.offloat(mtv2, translationy, 0, 400, 0); tv2translatey.setrepeatcount(valueanimator.infinite); animatorset animatorset = new animatorset(); animatorset.play(tv1translatey).with(tv2translatey).after(tv1bganimator); //添加listener animatorset.addlistener(new animator.animatorlistener() { @override public void onanimationstart(animator animation) { log.d(tag, animator start); } @override public void onanimationend(animator animation) { log.d(tag, animator end); } @override public void onanimationcancel(animator animation) { log.d(tag, animator cancel); } @override public void onanimationrepeat(animator animation) { log.d(tag, animator repeat); } }); animatorset.setduration(2000); animatorset.start(); return animatorset;}
这里着重注意两点:
第一:将动画tv2translatey设置为无限循环
第二:在animatorset添加的animator.animatorlistener()中每个部分添加上log
我们看一下对应的动画及log
对应的log
从效果图和对应中的log中也可以看到,虽然我们的tv2translatey动画在无限循环,但log中没有打印出对应的repeat的日志,从日志中也可以看出,animatorset的监听函数也只是用来监听animatorset的状态的,与其中的动画无关;
所以我们来总结一下animatorset的监听:
1、animatorset的监听函数也只是用来监听animatorset的状态的,与其中的动画无关;
2、animatorset中没有设置循环的函数,所以animatorset监听器中永远无法运行到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中的设置就会无效。
下面我们简单举个例子来看下
objectanimator tv1translatey = objectanimator.offloat(mtv1, translationy, 0, 400, 0);tv1translatey.setduration(500000000);tv1translatey.setinterpolator(new bounceinterpolator());objectanimator tv2translatey = objectanimator.offloat(mtv2, translationy, 0, 400, 0);tv2translatey.setinterpolator(new acceleratedecelerateinterpolator());animatorset animatorset = new animatorset();animatorset.play(tv2translatey).with(tv1translatey);animatorset.setduration(2000);animatorset.start();
在第这个例子中,我们通过animatorset.setduration(2000);设置为所有动画单词运动时长为2000毫秒,虽然我们给tv1translatey设置了单次动画时长为tv1translatey.setduration(500000000);但由于animatorset设置了setduration(2000)这个参数以后,单个动画的时长设置将无效。所以每个动画的时长为2000毫秒。
但我们这里还分别给tv1和tv2设置了加速器,但并没有给animatorset设置加速器,那么tv1,tv2将按各自加速器的表现形式做动画。
同样,如果我们给animatorset设置上了加速器,那么单个动画中所设置的加速器都将无效,以animatorset中的加速器为准。
效果图如下:
从动画中也可以看到,这两个控件同时开始,同时结束,这说明他们两个的单次动画的时长是一样的。也就是以animatorset.setduration(2000)为准的2000毫秒。
其次,这两个动画在运动过程中的表现形式是完全不一样的,这说明他们的加速器是不一样的。也就是在animatorset没有统一设置的情况下,各自按各自的来。
2、settarget(object target)示例 //设置objectanimator动画目标控件public void settarget(object target)
这里我们着重讲一下animatorset的settartget函数,这个函数是用来设置目标控件的,也就是说,只要通过animatorset的settartget函数设置了目标控件,那么单个动画中的目标控件都以animatorset设置的为准
我们来看个例子:
objectanimator tv1bganimator = objectanimator.ofint(mtv1, backgroundcolor, 0xffff00ff, 0xffffff00, 0xffff00ff);objectanimator tv2translatey = objectanimator.offloat(mtv2, translationy, 0, 400, 0);animatorset animatorset = new animatorset();animatorset.playtogether(tv1bganimator,tv2translatey);animatorset.setduration(2000);animatorset.settarget(mtv2);animatorset.start();
在这段代码中,我们给tv1设置了改变背景色,给tv2设置了上下移动。但由于我们通过animatorset.settarget(mtv2);将各个动画的目标控件设置为mtv2,所以tv1将不会有任何动画,所有的动画都会发生在tv2上。
效果图如下:
所以animatorset.settarget()的作用就是将动画的目标统一设置为当前控件,animatorset中的所有动画都将作用在所设置的target控件上
源码在文章底部给出
五、animatorset之setstartdelay(long startdelay) //设置延时开始动画时长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毫秒,所以在动画开始后,tv1会直接运动,但tv2要等2000毫秒以后,才会开始运动。
这里要特别提醒大家注意一行代码:
animatorset.play(tv1translatey).with(tv2translatey);
在这行代码中,我们play的是tv1!而且tv1是没有设置延时的!这里要非常注意一下,下面我们会深入的探讨这个问题。
我们来看看效果图:
在这个效果图中可以看到在点击了start anim按钮以后,动画并没有立即开始,这是因为我们给animatorset设置了延时;另外在animatorset延时过了以后,可以看到tv1立刻开始动画,但此时tv2并没有任何动静。这是因为我们单独给tv2又设置了延时。
所以从这里,我们可以得到一个结论:
animatorset的延时是仅针对性的延长animatorset激活时间的,对单个动画的延时设置没有影响。
示例二: 上面我们提示大家注意动画顺序,上面的动画顺序是
animatorset.play(tv1translatey).with(tv2translatey);
我们这里将动画顺序翻倒一下,看会是什么结果呢?
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(tv2translatey).with(tv1translatey);animatorset.setstartdelay(2000);animatorset.setduration(2000);animatorset.start();
我们先来看一下动画效果:
这个动画效果有没有感觉非常奇怪,这里的代码仅仅调换了play的顺序,却与上面的效果完全不一样!
按说这里的效果应该与上个的效果是一样的才对,即在animatorset被激活以后,tv1应该立即运行,等2000毫秒后tv2才开始运行。
但这里的效果却是过了一段时间以后,tv1和tv2一起运行!
这是因为:
animatorset真正激活延时 = animatorset.startdelay+第一个动画.startdelay
也就是说animatorset被激活的真正延时等于它本身设置的setstartdelay(2000)延时再上第一个动画的延时;
在真正的延时过了之后,动画被激活,这时相当于赛马场的每个跑道的门就打开了。每个动画就按照自己的动画处理来操作了,如果有延时就延时动画。但由于第一个动画的延时已经animatorset被用掉了,所以第一个动画就直接运行。
在这个例子中,由于只有tv1有延时,而在animatorset被激活后,tv1的延时被animatorset用掉了,所以tv1直接运行;而在animatorset激活后,由于tv2没有设置延时,所以tv2直接运动。
下面我们再举个例子,同样是上面的代码,我们如果给tv2加上延时会怎样:
objectanimator tv1translatey = objectanimator.offloat(mtv1, translationy, 0, 400, 0);tv1translatey.setstartdelay(2000);objectanimator tv2translatey = objectanimator.offloat(mtv2, translationy, 0, 400, 0);tv2translatey.setstartdelay(2000);animatorset animatorset = new animatorset();animatorset.play(tv2translatey).with(tv1translatey);animatorset.setstartdelay(2000);animatorset.setduration(2000);animatorset.start();
代码与上面的一样,只是不仅给tv2添加了延时,而且给tv1添加了延时。
效果图如下:
从效果图中也可以看到,由于animatorset激活延时 = animatorset.startdelay+第一个动画.startdelay;所以在4000毫秒后,动画被激活,tv2由于已经被用掉了延时,所以在激活后直接开始。但tv1则按照自己的设定,在动画激活后,延时2000毫秒后才开始动画;
经过上面的例子,我们可以得出以下结论:
- animatorset的延时是仅针对性的延长animatorset激活时间的,对单个动画的延时设置没有影响。
- animatorset真正激活延时 = animatorset.startdelay+第一个动画.startdelay
- 在animatorset激活之后,第一个动画绝对是会开始运行的,后面的动画则根据自己是否延时自行处理。
源码在文章底部给出
好了,这篇文章把animatorset相关的知识都讲完了,看似简单的知识,其实比较复杂。尤其是最后的延时部分,大家可以多看看源码,多试试这些函数的用法,应该就能理解出来。下篇将带大家来看动画的xml实现方式。
先出去玩了,晚上回来给出源码