Android属性动画 AnimatorSet

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真正意义

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

总结:

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

如何实现无限循环动画?

是否无限循环主要是看动画本身,与playSequentially/playTogether无关!
这句话有bug。这个分两个情况来解释,

  • 一是playTogether:在playTogether情况下,每个控件的所有动画是同时执行的,没有先后顺序之分,所以是否无限循环主要是看动画本身,与playTogether无关;
  • 二是playSequentially在执行顺序上有变化

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

通用方法逐个设置与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中的设置。

只要通过AnimatorSetsetTartget方法设置了目标控件,那么单个动画中的目标控件都以AnimatorSet设置的为准 ;

如前面的Builder顺序动画,我们给mTvAnimator01mTvAnimator02设置了改变背景色和上下移动的动画。但由于我们通过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();

转载:https://blog.csdn.net/zhaoyanjun6/article/details/118766558

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值