Android animation set ordering XML控制动画同时播放或顺序播放

1次阅读

animation-list仅支持逐帧播放,无法控制顺序;需用animationset(补间)或animatorset(属性动画)在代码中编排,后者推荐,支持play().with()/before()等动态时序控制。

Android animation set ordering XML控制动画同时播放或顺序播放

animation-list 里不能控制播放顺序,得用 AnimationSet

android 原生 animation-list 只支持逐帧播放(类似 GIF),不支持「同时播多个动画」或「指定先后顺序」。真要控制时序,必须用 Java/kotlin 代码配合 AnimationSet,或者改用更现代的 AnimatorSet(推荐)。

常见错误现象:AnimationDrawable 启动后只播第一帧、卡住、或所有动画叠在一起没效果——本质是误把帧动画当成了可编排的补间动画。

  • AnimationSet 是旧版补间动画(AlphaAnimationTranslateAnimation 等)的容器,支持 setStartOffset()setFillAfter(true) 控制时序和终态
  • AnimatorSet 是属性动画方案,用 play() + with() / before() / after() 显式编排,语义清晰、支持取消、性能更好
  • xml 中定义的 set 动画(如 res/anim/fade_and_move.xml)本质还是 AnimationSet,但无法动态调整顺序,写死在 XML 里就固定了

用 AnimatorSet.play().with() 实现同时播放

两个动画想一起动,比如按钮点击时既缩放又变透明,不能靠叠加多个 startAnimation() 调用——那样会抢 View 的动画控制器,后一个大概率覆盖前一个。

正确做法是把它们包进同一个 AnimatorSet,用 play().with() 声明并发关系:

AnimatorSet set = new AnimatorSet(); Animator scale = ObjectAnimator.ofFloat(view, "scaleX", 1f, 0.8f); Animator alpha = ObjectAnimator.ofFloat(view, "alpha", 1f, 0.5f); set.play(scale).with(alpha); // 同时开始、同时结束 set.start();
  • 注意:所有被 play() 包裹的动画,必须用同一个 View对象,否则运行时报 IllegalArgumentException: target must not be NULL
  • 如果动画时长不同,with() 仍会让它们同步启动,但各自按自己的时长执行;不需要手动对齐 duration
  • 别在 with() 里传 null 动画,否则整个 AnimatorSet 启动失败,log 里只报 java.lang.NullPointerException,没更多线索

用 AnimatorSet.play().before() 控制严格先后顺序

「先平移再旋转」这种依赖顺序的场景,before() 比手动设 startDelay 更可靠——它自动根据前一个动画的 duration 计算延迟,避免硬编码导致错位。

示例:View 先向右滑入,停顿 200ms,再顺时针转一圈:

ObjectAnimator translate = ObjectAnimator.ofFloat(view, "translationX", -view.getWidth(), 0); ObjectAnimator rotate = ObjectAnimator.ofFloat(view, "rotation", 0f, 360f); AnimatorSet set = new AnimatorSet(); set.play(translate).before(rotate); // translate 结束后,rotate 立即开始 // 如果需要中间停顿,加个 dummy animator 或用 set.startDelay() rotate.setStartDelay(200); // rotate 自己延后 200ms 启动 set.start();
  • before()after() 是相对关系,不是绝对时间轴;如果前面动画被取消,后面的不会自动触发
  • XML 定义的动画(如 res/anim/slide_in.xml)转成 Animator 后也能参与 play().before() 编排,用 AnimatorInflater.loadAnimator() 加载即可
  • 别混用 Animation(补间)和 Animator(属性)到同一个 AnimatorSet 里——编译不报错,运行直接 ClassCastException

XML 动画 set 文件里的 android:ordering=”sequentially” 是摆设

很多人在 res/anim/combined.xml 里写 android:ordering="sequentially",以为能控制子动画顺序,结果发现还是并行——因为这个属性只对旧版 AnimationSet XML 生效,且仅影响「同一层级子动画」的默认行为,实际仍受各子动画自身的 android:startOffset 支配。

更关键的是:从 Android 4.0+ 开始,系统对 XML AnimationSet 的解析逻辑有隐式优化,某些情况下会忽略 ordering,尤其当子动画没有显式 startOffset 时,默认当作 together 处理。

  • 真正可靠的顺序控制,只存在于代码中(AnimatorSet 或手动调 Animation.setStartOffset()
  • XML set 适合封装「固定组合、无需动态调整」的动画,比如一个按钮按下反馈:缩放 + 变色 + 震动,全写死在 XML 里没问题
  • 如果业务需要根据状态切换播放逻辑(比如网络加载中播旋转,失败后切为抖动),硬靠 XML + AnimationDrawable 基本做不到,必须上代码编排

事情说清了就结束。真正的难点不在语法,而在理解「XML 描述的是静态结构,而时序是运行时的动态关系」——只要记住这点,就不会再往 XML 里塞逻辑了。

text=ZqhQzanResources