如何重新启动Android的AnimatedVectorDrawables动画?

12

我有一个相当复杂的矢量图形,想要进行动画化处理。我使用了@RomanNurik 的Web工具,将svg文件转换成了动画。

这样就得到了一个有效的<animated-vector>,根据文档,它是一个“一体化”的XML文件。

XML文件将可绘制对象分为两个组,每个组包含2个路径,并添加了4个动画,如下:

<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:aapt="http://schemas.android.com/aapt">
    <aapt:attr name="android:drawable">
        <vector xmlns:android="http://schemas.android.com/apk/res/android"
            android:width="56dp"
            android:height="56dp"
            android:viewportHeight="56.0"
            android:viewportWidth="56.0">
            <group
                android:name="group_1"
                android:pivotX="25"
                android:pivotY="25">
                <path
                    android:name="path_3_1"
                    ... />
                <path
                    android:name="path"
                    ... />
            </group>
            <group
                android:name="group"
                android:pivotX="25"
                android:pivotY="25">
                <path
                    android:name="path_1"
                    ... />
                <path
                    android:name="path_2"
                    ... />
            </group>
        </vector>
    </aapt:attr>
    <target android:name="path">
        <aapt:attr name="android:animation">
            <set xmlns:android="http://schemas.android.com/apk/res/android">
                <objectAnimator
                    android:name="path"
                    ... />
                <objectAnimator
                    android:name="path"
                  .../>
            </set>
        </aapt:attr>
    </target>
    <target android:name="group_1">
        <aapt:attr name="android:animation">
            <set xmlns:android="http://schemas.android.com/apk/res/android">
                <objectAnimator
                    android:name="group_1"
                    ... />
                <objectAnimator
                    android:name="group_1"
                    ... />
                <objectAnimator
                    android:name="group_1"
                    ... />
                <objectAnimator
                    android:name="group_1"
                    ... />
            </set>
        </aapt:attr>
    </target>
    <target android:name="group">
        <aapt:attr name="android:animation">
            <set xmlns:android="http://schemas.android.com/apk/res/android">
                <objectAnimator
                    android:name="group"
                    ... />
                <objectAnimator
                    android:name="group"
                    ... />
                <objectAnimator
                    android:name="group"
                    ... />
                <objectAnimator
                    android:name="group"
                    ... />
            </set>
        </aapt:attr>
    </target>
    <target android:name="path_3_1">
        <aapt:attr name="android:animation">
            <set xmlns:android="http://schemas.android.com/apk/res/android">
                <objectAnimator
                    android:name="path_3_1"
                    ... />
                <objectAnimator
                    android:name="path_3_1"
                    ... />
            </set>
        </aapt:attr>
    </target>
</animated-vector>

问题一:

由于不同的ObjectAnimators具有不同的android:durationandroid:startOffset值,因此我不能使用android:repeatCount="infinite",否则在运行一段时间后动画会混乱。所以最好的方法是通过编程来重复它。

问题二:

无论是AnimatedVectorDrawableCompat还是AnimatedVectorDrawable都没有一个方法表明动画应该循环播放。

问题三:

AnimatedVectorDrawableCompat没有registerAnimationCallback()方法,因此我无法监听onAnimationEnd并重新启动动画。此时,我放弃了向后兼容。

问题四:

我目前使用的实现方法使用了AnimatedVectorDrawable中的registerAnimationCallback(),但仅在Android API 25上有效,即使这些方法已在API 23中添加。

AnimatedVectorDrawable drawable = (AnimatedVectorDrawable) context().getDrawable(R.drawable.long_press_anim);
imageView.setImageDrawable(drawable);
drawable.registerAnimationCallback(new Animatable2.AnimationCallback() {
    @Override
    public void onAnimationEnd(Drawable drawable) {
        super.onAnimationEnd(drawable);
        ((AnimatedVectorDrawable) drawable).start();
    }
});
drawable.start();

在 API 23 和 24 中,动画只会播放一次,不会重复。

有什么解决方法吗?我快要放弃了,准备使用烂掉的 PNG 序列代替。


1
使用正确的延迟时间postDelay一个处理器...这是唯一的解决方案。 - pdegand59
我之前尝试过使用AnimatedVectorDrawableCompat,但是它没有起作用。但是我可以确认,在API 21-25中,使用VectorDrawableCompat是有效的。 - Felipe Conde
现在支持库已经添加了registerAnimationCallback()函数。 - romkal
3个回答

17

官方的可行答案在这里:https://issuetracker.google.com/issues/64591234

这段代码适用于API 16及以上版本(可能也适用于14-15版本)。我正在使用支持库26.1.0和vectorDrawables.useSupportLibrary = true(这样我就可以在xml中引用矢量图形而不会崩溃)。

animatedVector = AnimatedVectorDrawableCompat.create(getContext(), R.drawable.animated_clock);
ringingAlarmImage.setImageDrawable(animatedVector);
final Handler mainHandler = new Handler(Looper.getMainLooper());
animatedVector.registerAnimationCallback(new Animatable2Compat.AnimationCallback() {
    @Override
    public void onAnimationEnd(final Drawable drawable) {
        mainHandler.post(new Runnable() {
            @Override
            public void run() {
                animatedVector.start();
            }
        });
    }
});
animatedVector.start();

1
链接中有一个简短的解释,与线程中事物发生的技术细节有关。 - Carson Holzheimer
工作得很好 ;) 谢谢。 - AREF
1
这应该被接受的答案并需更多点赞!这是我让动画循环的唯一方法。使用Handler现在可以正常工作。Android文档没有指明这种行为! - mpellegr

3

我也有同样的问题,所以我这样做:

// setup and set animation
AnimatedVectorDrawableCompat animatedVector = AnimatedVectorDrawableCompat.create(context, R.drawable.listening_vector_anim);
imageView.setImageDrawable(animatedVector);

// loop animation!
new Thread(() -> {
    while (imageView.isAttachedToWindow()) {
        try {
            imageView.post(() -> animatedVector.start());
            Thread.sleep(2000); //depends on your animation duration
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}).start();

当ImageView从窗口中移除时,该线程将会终止。


0

我提供一些技巧

问题1:使用android:repeatCount="0"使其无限循环,同时使用android:repeatMode="restart"或"reverse"。

问题2:ObjectAnimator中有循环。上面的第一个问题与此相同。

问题3:ObjectAnimator中有监听器。如果添加监听器,则可以观察onAnimationEnd或onAnimationStart。

如果您选择文档中提供的三个文件的另一种替代方案来处理AnimatedVectorDrawable,您会感到舒适。

这三个文件是1. VectorDrawable,2. AnimatedVectorDrawable和3.ObjectAnimator

AnimatedVectorDrawable链接其他两个文件。

Ray Wenderlich网站上有一篇很好的文章,其中包含火箭和doge动画:https://www.raywenderlich.com/173345/android-animation-tutorial-with-kotlin(带有Java代码)。

您也可以阅读Alex Lockwood先生在https://www.androiddesignpatterns.com/2016/11/introduction-to-icon-animation-techniques.html上发表的文章“图标动画技术介绍”。源代码也可在GitHub上获取。


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