Créer une animation par le changement d'image dans ImageView avec Minuterie (ou Gestionnaire)

Je veux créer une animation simple en changeant les images à l'intérieur d'une ImageView. Je ne veux pas utiliser AnimationDrawable parce que j'ai besoin de recevoir des événements lorsqu'une image a changé ou lorsque l'animation est arrêtée, pour être en mesure de jouer à l'envers, le redémarrer et ainsi de suite.

Mon problème est que les images ne change en fait l'évènement setImageDrawable est appelée (sur le thread principal). Si tout semble bien fonctionner si l'on excepte le fait que les cadres ne change pas (en fait juste un cadre est tracé, le premier).

Donc mon code:

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);
}

J'ai un AnimatedImageView objet dans ma mise en page en xml et dans mon activité je trouve par id et le début de l'animation sur cliquez sur:

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();
}
});

Des idées? 🙂 Merci.

OriginalL'auteur laurentiugh | 2013-10-02