在 API 21 和 22 中强制使用 AnimatedVectorDrawableCompat 以使用 registerAnimationCallback

mon*_*key 5 api animation android

我正在为支持 Android API 19-26 的应用程序使用可绘制动画矢量。为了重新启动动画(它是一个自定义循环加载动画),我使用 AnimatedVectorDrawable.registerAnimationCallback,在 onAnimationEnd 回调中重新启动动画。这适用于 API >= 23 并且由于 AnimatedVectorDrawableCompat 它也适用于 API 19。

但是,它不适用于 API 21 和 22,因为类 AnimatedVectorDrawable 已经存在于这些 API 中,但 registerAnimationCallback 方法仅在 API 23 中添加。如何强制运行 API 21 或 22 的设备改用 AnimatedVectorDrawableCompat他们的 AnimatedVectorDrawable 类,以便我可以使用 registerAnimationCallback?

这是我编写的用于为不同 API 版本启动动画的方法(在 Kotlin 中):

private fun startAnimation() {
  if (Build.VERSION.SDK_INT >= 23) {
    ((circular_progress.drawable as LayerDrawable)
        .findDrawableByLayerId(R.id.loading_circle) as AnimatedVectorDrawable).apply {
      registerAnimationCallback(@TargetApi(23)
      object : Animatable2.AnimationCallback() {
        override fun onAnimationEnd(drawable: Drawable?) {
          super.onAnimationEnd(drawable)
          this@apply.start()
        }

        override fun onAnimationStart(drawable: Drawable?) = super.onAnimationStart(drawable)
      })
    }.start()
  } else if (Build.VERSION.SDK_INT >= 21) {
    ((circular_progress.drawable as LayerDrawable)
        .findDrawableByLayerId(R.id.loading_circle) as AnimatedVectorDrawable).apply {
      start()

      // No registerAnimationCallback here =( 

    }
  } else {
    ((circular_progress.drawable as LayerDrawable)
        .findDrawableByLayerId(R.id.loading_circle) as AnimatedVectorDrawableCompat).apply {
      registerAnimationCallback(object :
          Animatable2Compat.AnimationCallback() {
        override fun onAnimationEnd(drawable: Drawable?) {
          super.onAnimationEnd(drawable)
          this@apply.start()
        }

        override fun onAnimationStart(drawable: Drawable?) = super.onAnimationStart(drawable)
      })
    }.start()
  }
}
Run Code Online (Sandbox Code Playgroud)

mon*_*key 6

好的,我找到了解决方案。之前用过这个LayerDrawable,在xml中定义为layer_list.xml:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/normal_drawable"/>
    <item android:id="@+id/loading_circle"
    android:drawable="@drawable/animated_vector_drawable"/>
</layer-list>
Run Code Online (Sandbox Code Playgroud)

第一项是法线矢量可绘制,第二项是动画矢量可绘制:

<animated-vector
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:drawable="@drawable/...">

    <target .../>

    <target .../>

</animated-vector>
Run Code Online (Sandbox Code Playgroud)

然后我将 LayerDrawable 设置为 ImageView,如下所示:

imageView.setImageResource(R.drawable.layer_list)
Run Code Online (Sandbox Code Playgroud)

这里的问题是动画矢量可绘制对象在 API 版本 21 和 22 中在内部实例化为 AnimatedVectorDrawable,但它应该是 AnimatedVectorDrawableCompat。

解决方案是以编程方式实例化LayerDrawable、普通drawable和vector drawable:

val normalDrawable = ContextCompat.getDrawable(context, R.drawable.normal_drawable)
val animatedDrawable = AnimatedVectorDrawableCompat.create(context, R.drawable.animated_vector_drawable)
val layeredList = LayerDrawable(arrayOf(normalDrawable, animatedDrawable))

imageView.setImageDrawable(layeredList)
Run Code Online (Sandbox Code Playgroud)

这里动画可绘制对象显式实例化为 AnimatedVectorDrawableCompat,因此可以使用 registerAnimationCallback 方法:

animatedDrawable.registerAnimationCallback(...)
Run Code Online (Sandbox Code Playgroud)