动画第八步-> AnimatorSet:联合动画的代码实现
极客学院Animation教程讲解的很详细,点击进入哦
这里为学习的整理和补充O(∩_∩)O
一、概念大述
想必大家都看到赛马,在赛马开始前,每个马都会被放在起点的小门后面,到点了,门打开,马开始一起往前跑。
- playTogether 只是一个时间点上一起开始,对于开始后,各个动画怎么操作就是他们自己的事了,至于各个动画结不结束也是他们自已的事了。所以最恰当的描述就是门只负责打开,打开之后马咋跑,门也管不着,最后,马回不回来跟门也没啥关系。门的责任只是到点就打开而已。
放在动画上,就是在激活动画之后,动画开始后的操作只是动画自己来负责。至于动画结不结束,也只有动画自己知道。
- playSequentially 的意义就是当一匹马回来以后,再放另一匹。那如果上匹马永远没回来,那下一匹马也永远不会被放出来。
放到动画上,就是把激活一个动画之后,动画之后的操作就是动画自己来负责了,这个动画结束之后,再激活下一个动画。如果上一个动画没有结束,那下一个动画就永远也不会被激活。
下面,我们就具体了解一下吧O(∩_∩)O~
二、基本用法
public void playSequentially(Animator... items);
public void playSequentially(List<Animator> items);
public void playTogether(Animator... items);
public void playTogether(List<Animator> items);
demo:(标注①②的地方此时忽略,在第三小节讲解)
//第一步,声明ObjectAnimator对象
colorOfView1 = ObjectAnimator.ofInt(view1, "backgroundColor", 0xffff00ff, 0xff00ff00);
translateOfView1 = ObjectAnimator.ofFloat(view1, "translationY", 0, -600);
//translateOfView1.setStartDelay(5000);③
translateOfView2 = ObjectAnimator.ofFloat(view2, "translationY", 0, 600);
rotateOfView2 = ObjectAnimator.ofFloat(view2, "rotation", 0, 300, 200);
//rotateOfView2.setStartDelay(2000);②
playSquentlyBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
playSquetially();
}
});
playTogetherBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
playTogether();
}
});
//依次播放,一个动画播放完毕后,才执行下一个
public void playSquetially() {
animatorSetS = new AnimatorSet();
animatorSetS.setDuration(3000);
animatorSetS.playSequentially(translateOfView1, colorOfView1, translateOfView2, rotateOfView2);
//animatorSetS.setStartDelay(1000);①
animatorSetS.start();
}
//一起开始,所有动画同时执行start方法
public void playTogether() {
animatorSetT = new AnimatorSet();
animatorSetT.setDuration(3000);
//animatorSetT.setTarget(view2);④
animatorSetT.playTogether(translateOfView1, colorOfView1, translateOfView2, rotateOfView2);
//animatorSetT.setStartDelay(1000);①
animatorSetT.start();
}
执行效果:
playSequentially
playTogether
注意:
animatorSet.setDuration(3000)将3000这个值赋值给了每个ObjectAnimator对象的setDuration()方法,但是,在API15上AnimatorSet.setDuration()方法并没有给它的子objectAnimator设置,解决方案是给每个add到animatorSet中的ObjectAnimator都设置自己的duration。(Android版本兼容问题)
三、延时这个坑~
1.将标注为①的代码注释去掉,执行 animatorSet.setStartDelay方法,该方法表示:门在1000ms之后打开,此时,马🐴开始往前跑。
2.此时,再将②标注的代码注释去掉,执行rotateOfView2.setStartDelay(2000),可以看到如下效果:
(门在1000ms之后打开,但是旋转动画这匹马等了2000ms才开始跑)
playSquentially.gif playTogether.gif
看到这里,可能有人要问了,坑呢?坑在哪里?这些很符合逻辑思维嘛,那接下来就一起踩坑吧Q_Q
- 咱们将③注释去掉,开始执行(看下边gif),咦?为啥其他马都不跑了?要再多等5000ms才开始跑,明明只有translateOfView1这匹马让他晚了5000ms呀?_?
表急,看下边⤵️:
AnimatorSet 激活延时 = AnimatorSet.startDelay+第一个动画.startDelay
所以,1000ms+5000ms=6000ms之后,门被打开,然而由于translateOfView1这第一号马被用掉了延时,所以6000ms后直接开始,然而rotateOfView2没有被用掉延时,所以rotateOfView2需要再等2000ms才能执行
四、其他方法
- setTarget方法
//设置 ObjectAnimator 动画目标控件
public void setTarget(Object target)
将注释④去掉,就发现所有的动画都在view2上执行了,view1没有了任何的动作。
2.AnimatorSet.Builder方法【注意注意】
Builder对象通过play(Animator)建立
//和前面动画一起执行
public Builder with(Animator anim)
//在该动画之前执行前面的动画
public Builder before(Animator anim)
//在该动画之后执行前面的动画
public Builder after(Animator anim)
//在延迟 n 毫秒之后执行动画
public Builder after(long delay)
demo:
animatorSet.play(anim1).with(anim2).after(anim3);
//执行结果是anim3执行完毕后,anim1和anim2一起执行,表弄错了-
3.其他方法
在 AnimatorSet 中还有几个函数:
//设置单次动画时长
public AnimatorSet setDuration(long duration);
//设置加速器
public void setInterpolator(TimeInterpolator interpolator)
//设置 ObjectAnimator 动画目标控件
public void setTarget(Object target)
注意:在 AnimatorSet 中设置以后,会覆盖单个 ObjectAnimator 中的设置;即如果 AnimatorSet 中没有设置,那么就以 ObjectAnimator 中的设置为准。如果 AnimatorSet 中设置以后,ObjectAnimator 中的设置就会无效。
4.addListner添加监听
1、AnimatorSet 的监听函数也只是用来监听 AnimatorSet 的状态的,与其中的动画无关;
2、AnimatorSet 中没有设置循环的函数,即setRepeatCount(ValueAnimator.INFINITE),所以 AnimatorSet 监听器中永远无法运行到 onAnimationRepeat()中!
5.cancel()方法取消动画