Есть ли способ прослушать конец анимации в AnimatedVectorDrawables

Я создал AnimatedVectorDrawable, он работает довольно хорошо, теперь я ищу способ изменить анимацию или скрыть вид после его завершения. Я надеялся, что там был слушатель, но это не похоже, что есть. Может кто-нибудь помочь?

РЕДАКТИРОВАТЬ

Так что я нашел обходной путь, но не очень элегантный способ. Что я сделал, так это создал поток и опросил, если анимация запущена.

new Runnable() {
    public void run() {
        while(mLoop) {
            if(mAnimatedVectorDrawable.isRunning()) {
                Thread.sleep(mPollingInterval);
            } else {
                mLoop = false;
                // TODO what ever
            }
        }
    }
};

Если кто-то найдет лучшее решение, пожалуйста, поделитесь.

4 ответа

Решение

Моим первым инстинктом было взять исходный код, добавить несколько обратных вызовов и создать из него пользовательский объект. Конечно, это означало бы отсутствие поддержки XML.

Оказывается, что AnimatedVectorDrawable использования VectorDrawable's частный метод (ы). Таким образом, этот подход не будет работать.

Мы могли бы создать простой класс-оболочку вокруг AnimatedVectorDrawable и добавить обратные вызовы:

public class AVDWrapper {

    private Handler mHandler;
    private Animatable mDrawable;
    private Callback mCallback;
    private Runnable mAnimationDoneRunnable = new Runnable() {

        @Override
        public void run() {
            if (mCallback != null)
                mCallback.onAnimationDone();
        }
    };

    public interface Callback {
        public void onAnimationDone();
        public void onAnimationStopped();
    }

    public AVDWrapper(Animatable drawable, 
                            Handler handler, Callback callback) {
        mDrawable = drawable;
        mHandler = handler;
        mCallback = callback;
    }

    // Duration of the animation
    public void start(long duration) {
        mDrawable.start();
        mHandler.postDelayed(mAnimationDoneRunnable, duration);
    }

    public void stop() {
        mDrawable.stop();
        mHandler.removeCallbacks(mAnimationDoneRunnable);

        if (mCallback != null)
            mCallback.onAnimationStopped();
    }
}

Ваш код будет выглядеть так:

final Drawable drawable = circle.getDrawable();
final Animatable animatable = (Animatable) drawable;

AVDWrapper.Callback callback = new AVDWrapper.Callback() {
        @Override
        public void onAnimationDone() {
            tick.setAlpha(1f);
        }

        @Override
        public void onAnimationStopped() {
          // Okay
        }
    };

AVDWrapper avdw = new AVDWrapper(animatable, mHandler, callback);
//animatable.start();
avdw.start(2000L);

tick.setAlpha(0f);
//tick.animate().alpha(1f).setStartDelay(2000).setDuration(1).start();

// One wrapper is sufficient if the duration is same
final Drawable drawable2 = tick.getDrawable();
final Animatable animatable2 = (Animatable) drawable2;
animatable2.start();

Но это именно то, что вы делаете с setStartDelay, Так что я не знаю, насколько это будет полезно.

Редактировать: Все это также может быть реализовано внутри расширенного AnimatedVectorDrawable. Но вы полностью потеряете поддержку xml.

Пока не пробовал, но в Android 6.0 для этого есть метод registerAnimationCallback из интерфейса Animatable2.

Редактировать: да это работает в эмуляторе Android 6.0:

mAnimatedVectorDrawable.registerAnimationCallback (new Animatable2.AnimationCallback(){
    public void onAnimationEnd(Drawable drawable){
        //Do something
    }
}

Edit2: похоже, что они не добавили поддержку для этого в AnimatedVectorDrawableCompat из библиотеки поддержки 23.2+:(

Edit3: похоже, это было добавлено в поддержку lib 25.3.0

Спасибо Карсон!

Странно, что нет прямого API для получения этого. Я полагаю, что обходной путь, который не включает переопределения, это просто найти анимацию в вашем наборе анимаций, которая занимает больше всего времени, а затем опубликовать отложенный запуск, чтобы скрыть представление.

int longestAnimationTime = 500; //miliseconds, defined in XML possibly?
drawable.start();
drawableView.postDelayed(new Runnable() {

        @Override
        public void run() {
            drawableView.setVisibility(View.GONE);
        }
}, longestAnimationTime);

Недостатком является то, что это требует жесткого кодирования вашего самого длинного времени анимации, но пока вы ссылаетесь на одно и то же постоянное значение как в XML-анимации, так и в коде, оно будет работать правильно, никаких переопределений не требуется.

Я нашел ту же проблему. Я пытаюсь оживить нарисованный круг и галочку внутри.

Лучшее, что я мог сделать, это играть с продолжительностью. Что-то вроде этого:

final Drawable drawable = circle.getDrawable();
final Animatable animatable = (Animatable) drawable;
animatable.start();

tick.setAlpha(0f);
tick.animate().alpha(1f).setStartDelay(2000).setDuration(1).start();
final Drawable drawable2 = tick.getDrawable();
final Animatable animatable2 = (Animatable) drawable2;
animatable2.start();

Было бы здорово иметь слушателя

Другие вопросы по тегам