通过使用Timer(或Handler)在ImageView中更改图像来创建动画

时间:2013-10-02 20:33:43

标签: android animation android-imageview android-drawable animationdrawable

我想通过更改ImageView中的帧来创建一个简单的动画。我不想使用AnimationDrawable,因为我需要在帧更改或动画停止时接收事件,以便能够向后播放,重新启动它等等。

我的问题是虽然setImageDrawable被调用(在主线程上),但帧实际上并没有改变事件。因此,除了框架不会改变(实际上只绘制一个框架,第一个框架)之外,每个细节似乎都能正常工作。

所以我的代码:

public class AnimatedImageView extends ImageView implements Animatable, Runnable {

    private static final String TAG = "AnimatedImageView";

    public static interface AnimationEventsListener {
        void animationDidChangeFrame(AnimatedImageView animatedImageView);

        void animationDidStop(AnimatedImageView animatedImageView);
    }

    /* frames - ress ids */
    private int[] mFrameResIds;
    /* current frame index */
    private int mCurrentFrameIdx;
    /* number of the current repeat */
    private int loopIndex;
    /* number of animation repetiotions, 0 for infinite */
    private int mNumOfRepetitions;
    /* if animation is playing */
    private boolean playing;
    /* if animation is paused */
    private boolean paused;
    /* if animation is playing backward */
    private boolean playItBackward;
    /* animation duration */
    private long mAnimationDuration;
    /* frame animation duration (mAnimationDuration / num_of_frames) */
    private long mFrameAnimationDuration;

    /* listener for animation events */
    private AnimationEventsListener mListener;

    private Handler mHandler;

    public AnimatedImageView(Context context) {
        super(context);
        setup();
    }

    public AnimatedImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setup();
    }

    public AnimatedImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setup();
    }

    private void setup() {
        mHandler = new Handler(Looper.getMainLooper());
        this.setClickable(true);
        Logger.d("MSG", "setup, thread: " + Thread.currentThread().toString());
    }


    @Override
    public void start() {
        if (playing) {
            return;
        }
        mCurrentFrameIdx = playItBackward ? mFrameResIds.length - 1 : 0;
        loopIndex = 0;
        playing = true;
        updateFrame();
    }

    @Override
    public void stop() {
        paused = true;
    }

    public void resume() {
        paused = false;
        playing = true;
        updateFrame();
    }

    @Override
    public boolean isRunning() {
        return false;
    }

    @Override
    public void run() {
        Logger.d("MSG", "run, thread: " + Thread.currentThread().toString());
        updateFrame();
    }

    public AnimationEventsListener getListener() {
        return mListener;
    }

    public void setListener(AnimationEventsListener mListener) {
        this.mListener = mListener;
    }

    public long getAnimationDuration() {
        return mAnimationDuration;
    }

    public void setAnimationDuration(long mAnimationDuration) {
        this.mAnimationDuration = mAnimationDuration;
        if (mFrameResIds != null) {
            mFrameAnimationDuration = mAnimationDuration / mFrameResIds.length;
        }
    }

    public int[] getFrameResIds() {
        return mFrameResIds;
    }

    public void setFrameResIds(int[] mFrameResIds) {
        this.mFrameResIds = mFrameResIds;
        if (mFrameResIds != null) {
            mFrameAnimationDuration = mAnimationDuration / mFrameResIds.length;
        }
    }

    private void setCurrentFrame(int frameValue) {
        mCurrentFrameIdx = frameValue;
        this.setAnimationFrame(frameValue);
    }

    private void setAnimationFrame(int animationFrame) {
        Logger.d("MSG", "setAnimationFrame: " + animationFrame);
        if (animationFrame < 0) {
            animationFrame = 0;
        }

        if (animationFrame > -1) {
            animationFrame = mFrameResIds.length - 1;
        }

        Resources resources = getResources();
        AnimatedImageView.this.setImageDrawable(resources.getDrawable(mFrameResIds[animationFrame]));
        AnimatedImageView.this.forceLayout();
//        AnimatedImageView.this.setImageBitmap(BitmapFactory.decodeResource(resources, mFrameResIds[animationFrame]));
//        this.setImageResource(mFrameResIds[animationFrame]);
        AnimatedImageView.this.invalidate();
    }

    private void updateFrame() {
        Logger.d("MSG", "updateFrame " + mCurrentFrameIdx);
        if (!playing || paused) {
            return;
        }

        playing = false;

        if (mListener != null) {
            mListener.animationDidChangeFrame(AnimatedImageView.this);
        }

        if (!playItBackward) {
            mCurrentFrameIdx++;
            if (mCurrentFrameIdx >= mFrameResIds.length) {
                loopIndex++;
                mCurrentFrameIdx = 0;
                if (mNumOfRepetitions == loopIndex) {
                    if (mListener != null) {
                        mListener.animationDidStop(AnimatedImageView.this);
                    }
                    return;
                }
            }
        } else {
            mCurrentFrameIdx--;
            if (mCurrentFrameIdx < 0) {
                loopIndex++;
                mCurrentFrameIdx = mFrameResIds.length - 1;
                if (mNumOfRepetitions == loopIndex) {
                    if (mListener != null) {
                        mListener.animationDidStop(AnimatedImageView.this);
                    }
                    return;
                }
            }
        }

        playing = true;

        setAnimationFrame(mCurrentFrameIdx);
//        mHandler.postDelayed(AnimatedImageView.this, mFrameAnimationDuration);
//        scheduleDrawable(getResources().getDrawable(mFrameResIds[mCurrentFrameIdx]), AnimatedImageView.this, mFrameAnimationDuration);
//        postDelayed()
        postDelayed(AnimatedImageView.this, mFrameAnimationDuration);

//        SongPlayerActivity.handler.postDelayed(AnimatedImageView.this, mFrameAnimationDuration);
    }

我在xml的布局中有一个AnimatedImageView对象,在我的活动中,我通过id找到它并在点击时启动动画:

final AnimatedImageView mDriverAnimation = (AnimatedImageView) findViewById(R.id.driver);
        mDriverAnimation.setFrameResIds(new int[]{R.drawable.song1_driver1, R.drawable.song1_driver2, R.drawable.song1_driver3});
        mDriverAnimation.setAnimationDuration(3 * 1000);
        mDriverAnimation.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                mDriverAnimation.start();
            }
        });

有什么想法吗? :)谢谢。

1 个答案:

答案 0 :(得分:7)

我认为TransitionDrawable可以解决您的问题:http://developer.android.com/reference/android/graphics/drawable/TransitionDrawable.html

Drawable[] layers = new Drawable[2];
layers[0] = //your first drawable
layers[1] = //your second drawable
TransitionDrawable transition = new TransitionDrawable(layers);
myImageView.setImageDrawable(transition);
transition.startTransition(1500);