AnimatedVectorDrawableCompat循环动画API21-24无法重复问题咨询
解决AnimatedVectorDrawableCompat在API21-24上仅播放一次的循环问题
我来帮你搞定这个兼容性问题,先分析下原因,再给几个非hack的可靠方案:
问题原因
这是旧版本AnimatedVectorDrawableCompat在API21-24上的已知实现缺陷:当动画结束触发onAnimationEnd回调时,内部的动画状态还没完全重置完成,此时直接调用start()虽然会执行方法,但无法正确重启动画。而API25+的系统和Compat库修复了这个状态同步的问题,所以表现正常。
非hack解决方案
方案1:延迟重启动画(最简单的修复)
利用View的post()方法,把重启动画的操作放到下一次UI消息循环中,让系统有足够时间完成动画状态的重置:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); imageView = findViewById(R.id.image_view1); final AnimatedVectorDrawableCompat anim = AnimatedVectorDrawableCompat.create(this, R.drawable.avd_pass_inside); imageView.setImageDrawable(anim); anim.registerAnimationCallback(new Animatable2Compat.AnimationCallback() { @Override public void onAnimationEnd(Drawable drawable) { // 用post把重启操作放到UI线程的消息队列末尾 imageView.post(() -> { if (anim.isRunning()) { anim.stop(); } anim.start(); }); } }); anim.start(); }
方案2:用ValueAnimator手动控制循环(最稳定的方案)
直接绕过AnimatedVectorDrawable的自动循环,用ValueAnimator来驱动动画进度,这种方式在所有API版本上表现一致:
private AnimatedVectorDrawableCompat anim; private ValueAnimator loopAnimator; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); imageView = findViewById(R.id.image_view1); anim = AnimatedVectorDrawableCompat.create(this, R.drawable.avd_pass_inside); imageView.setImageDrawable(anim); // 创建循环动画控制器 loopAnimator = ValueAnimator.ofFloat(0f, 1f); // 获取AVD的默认时长作为动画周期 loopAnimator.setDuration(anim.getIntrinsicDuration()); // 设置无限循环 loopAnimator.setRepeatCount(ValueAnimator.INFINITE); loopAnimator.addUpdateListener(animation -> { float progress = (float) animation.getAnimatedValue(); anim.setProgress(progress); }); loopAnimator.start(); } // 记得在生命周期里管理动画,避免内存泄漏 @Override protected void onPause() { super.onPause(); if (loopAnimator != null && loopAnimator.isRunning()) { loopAnimator.pause(); } } @Override protected void onResume() { super.onResume(); if (loopAnimator != null && loopAnimator.isPaused()) { loopAnimator.resume(); } } @Override protected void onDestroy() { super.onDestroy(); if (loopAnimator != null) { loopAnimator.cancel(); loopAnimator = null; } }
方案3:升级AppCompat库版本
如果你的项目使用的AppCompat版本比较旧,升级到1.3.0及以上版本可能已经修复了这个兼容性bug:
在你的build.gradle(Module级别)中更新依赖:
implementation 'androidx.appcompat:appcompat:1.6.1'
额外注意事项
- 记得在Activity的生命周期方法(
onPause/onResume/onDestroy)中管理动画的状态,避免后台耗电或内存泄漏; - 不要在非UI线程操作动画,虽然你提到动画运行在非UI线程不阻塞界面,但AnimatedVectorDrawable的状态更新最好还是在UI线程进行,避免潜在的状态异常。
内容的提问来源于stack exchange,提问作者tplive
相关产品推荐
相关产品推荐

