22

私は AnimatedVectorDrawable を作成しました。これはかなりうまく機能します。現在、アニメーションを変更したり、終了後にビューを非表示にしたりする方法を探しています。リスナーがいることを願っていましたが、そうではないようです。誰か助けてくれませんか?

編集

そのため、回避策を見つけましたが、あまりエレガントな方法ではありません。私がしたことは、スレッドを作成し、アニメーションが実行されているかどうかをポーリングすることでした。

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

誰かがより良い解決策を見つけたら、共有してください。

4

4 に答える 4

19

これはまだ試していませんが、Android 6.0 にはAnimatable2 インターフェイスからのregisterAnimationCallbackメソッドがあります。

編集: はい、これは Android 6.0 エミュレーターで動作します:

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

Edit2: サポート ライブラリ 23.2+ から AnimatedVectorDrawableCompat にこれのサポートが追加されていないようです:(

Edit3: これはサポート ライブラリ 25.3.0 に追加されたようです

ありがとうカーソン!

于 2015-09-26T16:44:49.680 に答える
8

私の最初の直感は、ソース コードを取得し、いくつかのコールバックを追加して、そこからカスタム ドローアブルを作成することでした。もちろん、それは 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 サポートは完全に失われます。

于 2015-03-07T02:19:47.720 に答える
4

これを取得するための直接の 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 とコードの両方で同じ定数値を参照している限り、正しく動作し、オーバーライドは必要ありません。

于 2015-03-12T18:47:02.937 に答える