转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/118766558
本文出自【赵彦军的博客】
文章目录
Android属性动画 ObjectAnimator
Android属性动画 Interpolator
Android 属性动画常见效果收集
Android ConstraintLayout ConstraintSet动态布局
AnimatorSet
实现组合动画功能主要需要借助AnimatorSet
这个类.
playTogether
多个动画一起执行。
var myView: Button = findViewById(R.id.bt)
var rotation = ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f)
var translationX = ObjectAnimator.ofFloat(myView, "translationX", 0f, 360f)
val set = AnimatorSet()
set.playTogether(rotation, translationX)
set.duration = 2000
set.interpolator = LinearInterpolator()
set.start()
playSequentially
多个动画顺序执行。
var myView: Button = findViewById(R.id.bt)
var rotation = ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f)
var translationX = ObjectAnimator.ofFloat(myView, "translationX", 0f, 360f)
val set = AnimatorSet()
set.playSequentially(rotation, translationX)
set.duration = 2000
set.interpolator = LinearInterpolator()
set.start()
after(Animator anim)
将现有动画插入到传入的动画之后执行
var myView: Button = findViewById(R.id.bt)
var rotation = ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f)
var translationX = ObjectAnimator.ofFloat(myView, "translationX", 0f, 360f)
val set = AnimatorSet()
set.play(rotation).after(translationX)
set.duration = 2000
set.interpolator = LinearInterpolator()
set.start()
把 旋转动画
插入到 平移动画
之后。所以总体效果是:先执行平移动画,然后再执行旋转动画
before(Animator anim)
将现有动画插入到传入的动画之前执行。
var myView: Button = findViewById(R.id.bt)
var rotation = ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f)
var translationX = ObjectAnimator.ofFloat(myView, "translationX", 0f, 360f)
val set = AnimatorSet()
set.play(rotation).before(translationX)
set.duration = 2000
set.interpolator = LinearInterpolator()
set.start()
把 旋转动画
插入到 平移动画
之前。所以总体效果是:先执行旋转动画,然后再执行平移动画
after(long delay)
将现有动画插入到传入的动画之后执行。相当于延迟执行。
var rotation = ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f)
var translationX = ObjectAnimator.ofFloat(myView, "translationX", 0f, 360f)
val set = AnimatorSet()
set.play(rotation).before(translationX).after(2000)
set.duration = 2000
set.interpolator = LinearInterpolator()
set.start()
先把 rotation 放在 translationX 之前,执行顺序是:rotation -> translationX
然后把整体动画放在 after(2000) 之后,执行顺序是 :延迟 2 秒 -> rotation -> translationX
with(Animator anim)
多个动画同时执行。
var myView: Button = findViewById(R.id.bt)
var rotation = ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f)
var translationX = ObjectAnimator.ofFloat(myView, "translationX", 0f, 360f)
var alpha = ObjectAnimator.ofFloat(myView, "alpha", 0f, 1f)
val set = AnimatorSet()
set.play(rotation).with(translationX).after(alpha)
set.duration = 2000
set.interpolator = LinearInterpolator()
set.start()
旋转动画 和 平移动画一起执行,然后整体放在 alpha 动画后面。所以整体执行顺序是:先执行 alpha 动画,然后一起执行 旋转动画、平移动画。
注意事项
playSequentially、playTogether真正意义
playTogether
和playSequentially
在开始动画时,只是把每个控件的动画激活,至于每个控件自身的动画是否具有延时、是否无限循环,只与控件自身的动画设定有关,与playTogether
、playSequentially
无关。playTogether
和playSequentially
只负责到点激活动画。
总结:
- 第一:
playTogether
和playSequentially
在激活动画后,控件的动画情况与它们无关,他们只负责定时激活控件动画。 - 第二:
playSequentially
只有控件的上一个动画做完以后,才会激活控件的下一个动画,如果控件的上一动画是无限循环,那控件的下一个动画甚至下一个控件的动画就别再指望了。
如何实现无限循环动画?
是否无限循环主要是看动画本身,与playSequentially
/playTogether
无关!
这句话有bug。这个分两个情况来解释,
- 一是
playTogether
:在playTogether
情况下,每个控件的所有动画是同时执行的,没有先后顺序之分,所以是否无限循环主要是看动画本身,与playTogether
无关; - 二是
playSequentially
在执行顺序上有变化
AnimatorSet
没有setRepeatCount
方法,只是通过playTogether
和playSequentially
负责指定什么时候开始动画,不干涉动画自己的运行过程。换言之:playTogether
和playSequentially
只是赛马场上的每个赛道的门,门打开以后,赛道上的那匹马怎么跑跟它没什么关系。
通用方法逐个设置与AnimatorSet设置的区别
在 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
中的设置。
只要通过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激活之后,第一个动画绝对是会开始运行的,后面的动画则根据自己是否延时自行处理。
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();