在Nougat中无法将类型转换为AnimatedVectorDrawableCompat

16

这是我的 build.gradle 文件

    defaultConfig {
    ...
    minSdkVersion 21
    targetSdkVersion 26
    vectorDrawables.useSupportLibrary = true
}

以及布局的一部分

<ImageView
    android:id="@+id/recents"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="?attr/selectableItemBackground"
    android:clickable="true"
    android:scaleType="fitCenter"
    app:srcCompat="@drawable/anim_test"/>

和类转换:

val np = convertView.findViewById<ImageView>(R.id.recents)
val anim = np.drawable as AnimatedVectorDrawableCompat

这在Lolipop(sdk 21)上按预期工作,但在Nougat上失败,显示以下消息:

android.graphics.drawable.AnimatedVectorDrawable cannot be cast to android.support.graphics.drawable.AnimatedVectorDrawableCompat
我不理解的是,为什么在SDK 21级别上返回AnimatedVectorDrawableCompat,当系统已经支持AnimatedVectorDrawable。而且,尽管指定了,在Nougat中它也会返回AnimatedVectorDrawable。

1
相同的问题出现在支持库26.0.1中。通过一种解决方法解决:在运行时添加一个条件 - 对于Lollipop及以上版本,您需要将AnimatedVectorDrawable强制转换为AnimatedVectorDrawableCompat以适用于之前的Lollipop版本。 - Blo
5个回答

18

简短回答:

使用 AnimatedVectorDrawableCompat.registerAnimationCallback 静态方法,它会为您完成任务。

(drawable as Animatable).start()

AnimatedVectorDrawableCompat.registerAnimationCallback(
        drawable,
        object : Animatable2Compat.AnimationCallback() {
            override fun onAnimationEnd(drawable: Drawable?) {
                postOnAnimation {
                    (drawable as Animatable).start()
                }
            }
        })
   

长的回答:

当我尝试循环一个动态矢量图形时,我遇到了同样的问题。直到我发现支持库在不同的SDK级别上返回不同的类(AnimatedVectorDrawableAnimatedVectorDrawableCompat)。

除了Nick Butcher这篇精彩的博客文章之外,没有任何文档记录这一点:

https://medium.com/androiddevelopers/re-animation-7869722af206

他说:

有趣的是目前支持库在API 24+上使用本机版本,在API 21及更早期的兼容版本中使用它,尽管该类是在API 21中引入的。这使其能够为API 21-23提供错误修复。

在博客文章中,作者还建议其他解决此问题的方法,例如使用AnimatedVectorDrawableCompat#create方法和在运行时设置可绘制对象。

我建议你阅读整篇文章。

希望这可以帮助你。


1
这个正常工作。在我的情况下,我错误地使用了矢量可绘制的图片来设置imageView,而不是动画drawable。例如:iv.setImageResource(R.drawable.ic_non_animated) 你应该将这段代码更改为 iv.setImageResource(R.drawable.ic_animated) - mochadwi

14

不必再使用 API<21 的检查,因为 AnimatedVectorDrawableAnimatedVectorDrawableCompat 都实现了 Animatable 接口,你可以进行强制类型转换

var anim = mImageView.drawable as Animatable
    anim.start()

5
我会这样处理它:
public class MainActivity extends AppCompatActivity {
    ImageView img;
    Button show, play, stop;
    AnimatedVectorDrawableCompat anim_show, anim_play, anim_stop;
    Object canim_show, canim_play, canim_stop;

    static {
        AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        img = findViewById(R.id.img);

        show = findViewById(R.id.show);
        play = findViewById(R.id.play);
        stop = findViewById(R.id.stop);

        if (Build.VERSION.SDK_INT < 21 ) {
            anim_show = (AnimatedVectorDrawableCompat) getResources().getDrawable(R.drawable.xunfei_show_animated_vector);
            anim_play = (AnimatedVectorDrawableCompat) getResources().getDrawable(R.drawable.xunfei_play_animated_vector);
            anim_stop = (AnimatedVectorDrawableCompat) getResources().getDrawable(R.drawable.xunfei_stop_animated_vector);

        }else{
            canim_show = (AnimatedVectorDrawable) getResources().getDrawable(R.drawable.xunfei_show_animated_vector);
            canim_play = (AnimatedVectorDrawable) getResources().getDrawable(R.drawable.xunfei_play_animated_vector);
            canim_stop = (AnimatedVectorDrawable) getResources().getDrawable(R.drawable.xunfei_stop_animated_vector);
        }

        show.setOnClickListener(new View.OnClickListener() {
            @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
            @Override
            public void onClick(View view) {
                if (Build.VERSION.SDK_INT < 21) {
                    img.setImageDrawable(anim_show);
                    anim_show.start();
                } else {
                    img.setImageDrawable((AnimatedVectorDrawable) canim_show);
                    ((AnimatedVectorDrawable) canim_show).start();
                }

            }
        });
    }
}

2

虽然有些晚了,但我刚遇到了类似的问题,并已经解决了。也许对某人有帮助。

当我们在动画中使用 vectorDrawables 时,需要执行以下三个步骤:

  1. 从矢量可绘制资源创建一个 AnimatedVectorDrawableCompat:
val drawable: AnimatedVectorDrawableCompat? =
          AnimatedVectorDrawableCompat.create(context, R.drawable.animated_vector)

将此可绘制对象转换为Animatable2Compat:
val animatable: Animatable2Compat = drawable as Animatable2Compat

现在注册支持提供的回调函数。
animatable.registerAnimationCallback(object : Animatable2Compat.AnimationCallback() {
    override fun onAnimationEnd(drawable: Drawable?) {
      // Put code to execute after the animation is done
    }
  })

这是我所做的事情。如果有更好的方法,请随意评论。

0
感谢 SafaOrhan 提供的可行示例。
我将发布带有导入的Java版本。
我使用了一个类成员变量,以便能够从另一个方法停止动画。
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Animatable;
import android.support.graphics.drawable.Animatable2Compat.AnimationCallback;
import android.support.graphics.drawable.AnimatedVectorDrawableCompat;
import android.os.Handler;

public class MainActivity {
  private Animatable vectorAnimation;

  public void stopAnimation() {
    if (vectorAnimation != null) vectorAnimation.stop();
  }

  public void startAnimation() {
    Drawable vectorDrawable = imageView.getDrawable();
    vectorAnimation = (Animatable) vectorDrawable;
    AnimatedVectorDrawableCompat.registerAnimationCallback(vectorDrawable, new AnimationCallback() {
      public void onAnimationEnd(Drawable drawable) {
        new Handler().postDelayed(() -> vectorAnimation.start(), 1000);
      }
    });
    vectorAnimation.start();
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接