如何实现三个TextView依次逐个执行动画?
实现三个TextView顺序执行动画的方案
嘿,这个需求很常见,核心就是监听前一个动画的结束事件,再启动下一个。我给你两种可行的实现方式,适配不同的动画类型:
方法一:利用传统Animation的监听器(适配你现有的XML动画)
你已经写好的XML动画没问题,我们只需要给每个动画绑定AnimationListener,在onAnimationEnd回调里触发下一个TextView的动画即可。
步骤1:确保你的动画XML放在res/anim/目录下(比如命名为slide_anim.xml)
你的动画代码如下:
<set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:fromXDelta="-5" android:toXDelta="15" android:repeatCount="15" android:repeatMode="reverse" android:interpolator="@android:anim/linear_interpolator" android:duration="70" /> </set>
步骤2:在Activity/Fragment中编写逻辑
Java版本:
// 获取三个TextView实例 TextView tv1 = findViewById(R.id.textView1); TextView tv2 = findViewById(R.id.textView2); TextView tv3 = findViewById(R.id.textView3); // 封装动画加载方法,避免重复代码 private Animation getSlideAnimation() { return AnimationUtils.loadAnimation(this, R.anim.slide_anim); } // 启动第一个动画,并设置监听器 Animation firstAnim = getSlideAnimation(); firstAnim.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) {} @Override public void onAnimationEnd(Animation animation) { // 第一个动画结束,启动第二个 Animation secondAnim = getSlideAnimation(); secondAnim.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) {} @Override public void onAnimationEnd(Animation animation) { // 第二个动画结束,启动第三个 tv3.startAnimation(getSlideAnimation()); } @Override public void onAnimationRepeat(Animation animation) {} }); tv2.startAnimation(secondAnim); } @Override public void onAnimationRepeat(Animation animation) {} }); tv1.startAnimation(firstAnim);
Kotlin版本:
val tv1 = findViewById<TextView>(R.id.textView1) val tv2 = findViewById<TextView>(R.id.textView2) val tv3 = findViewById<TextView>(R.id.textView3) // 封装动画加载方法 private fun getSlideAnimation() = AnimationUtils.loadAnimation(this, R.anim.slide_anim) // 启动第一个动画 val firstAnim = getSlideAnimation().apply { setAnimationListener(object : Animation.AnimationListener { override fun onAnimationStart(animation: Animation?) {} override fun onAnimationEnd(animation: Animation?) { // 启动第二个动画 getSlideAnimation().apply { setAnimationListener(object : Animation.AnimationListener { override fun onAnimationStart(animation: Animation?) {} override fun onAnimationEnd(animation: Animation?) { // 启动第三个动画 tv3.startAnimation(getSlideAnimation()) } override fun onAnimationRepeat(animation: Animation?) {} }) tv2.startAnimation(this) } } override fun onAnimationRepeat(animation: Animation?) {} }) } tv1.startAnimation(firstAnim)
方法二:使用属性动画的AnimatorSet(更简洁,推荐Android 3.0+使用)
如果你不需要兼容老版本,属性动画会更灵活,而且能直接改变View的真实属性(比如点击区域会跟着动画移动)。我们可以用AnimatorSet.playSequentially()直接让三个动画按顺序执行:
Java版本:
TextView tv1 = findViewById(R.id.textView1); TextView tv2 = findViewById(R.id.textView2); TextView tv3 = findViewById(R.id.textView3); // 创建每个TextView的平移动画 ObjectAnimator tv1Anim = ObjectAnimator.ofFloat(tv1, "translationX", -5f, 15f); tv1Anim.setDuration(70); tv1Anim.setRepeatCount(15); tv1Anim.setRepeatMode(ValueAnimator.REVERSE); tv1Anim.setInterpolator(new LinearInterpolator()); ObjectAnimator tv2Anim = ObjectAnimator.ofFloat(tv2, "translationX", -5f, 15f); tv2Anim.setDuration(70); tv2Anim.setRepeatCount(15); tv2Anim.setRepeatMode(ValueAnimator.REVERSE); tv2Anim.setInterpolator(new LinearInterpolator()); ObjectAnimator tv3Anim = ObjectAnimator.ofFloat(tv3, "translationX", -5f, 15f); tv3Anim.setDuration(70); tv3Anim.setRepeatCount(15); tv3Anim.setRepeatMode(ValueAnimator.REVERSE); tv3Anim.setInterpolator(new LinearInterpolator()); // 按顺序执行三个动画 AnimatorSet animatorSet = new AnimatorSet(); animatorSet.playSequentially(tv1Anim, tv2Anim, tv3Anim); animatorSet.start();
Kotlin版本:
val tv1 = findViewById<TextView>(R.id.textView1) val tv2 = findViewById<TextView>(R.id.textView2) val tv3 = findViewById<TextView>(R.id.textView3) // 构建每个动画 val tv1Anim = ObjectAnimator.ofFloat(tv1, "translationX", -5f, 15f).apply { duration = 70 repeatCount = 15 repeatMode = ValueAnimator.REVERSE interpolator = LinearInterpolator() } val tv2Anim = ObjectAnimator.ofFloat(tv2, "translationX", -5f, 15f).apply { duration = 70 repeatCount = 15 repeatMode = ValueAnimator.REVERSE interpolator = LinearInterpolator() } val tv3Anim = ObjectAnimator.ofFloat(tv3, "translationX", -5f, 15f).apply { duration = 70 repeatCount = 15 repeatMode = ValueAnimator.REVERSE interpolator = LinearInterpolator() } // 顺序执行 AnimatorSet().apply { playSequentially(tv1Anim, tv2Anim, tv3Anim) start() }
两种方法各有优劣:
- 传统视图动画(方法一):适合兼容老版本,代码和你的XML动画完全匹配,但不会改变View的真实位置,如果TextView需要响应点击,可能会有问题。
- 属性动画(方法二):更现代,能改变View的真实属性,交互更准确,代码也更简洁,推荐优先使用。
内容的提问来源于stack exchange,提问作者joker
相关产品推荐
相关产品推荐

