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

animation-list 里不能控制播放顺序,得用 AnimationSet
android 原生 animation-list 只支持逐帧播放(类似 GIF),不支持「同时播多个动画」或「指定先后顺序」。真要控制时序,必须用 Java/kotlin 代码配合 AnimationSet,或者改用更现代的 AnimatorSet(推荐)。
常见错误现象:AnimationDrawable 启动后只播第一帧、卡住、或所有动画叠在一起没效果——本质是误把帧动画当成了可编排的补间动画。
-
AnimationSet是旧版补间动画(AlphaAnimation、TranslateAnimation等)的容器,支持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 里塞逻辑了。