5

Chcę utworzyć prostą animację, zmieniając ramki wewnątrz ImageView. Nie chcę używać AnimationDrawable, ponieważ potrzebuję odbierać zdarzenia po zmianie klatki lub po zatrzymaniu animacji, aby móc odtwarzać ją wstecz, zrestartować i tak dalej.Tworzenie animacji przez zmianę obrazu w ImageView za pomocą Timera (lub Handler'a)

Problem polega na tym, że ramki nie zmieniają zdarzenia, mimo że wywoływana jest setImageDrawable (w głównym wątku). Tak więc wszystko wydaje się działać dobrze, z wyjątkiem tego, że klatki się nie zmieniają (właściwie tylko ramka jest rysowana, pierwsza).

Więc mój kod:

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

mam obiektu AnimatedImageView w moim układzie XML i moim aktywności go znaleźć przez id i uruchomić animację na kliknij:

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

jakieś pomysły ? :) Dzięki.

Odpowiedz

6

myślę że TransitionDrawable może rozwiązać swój problem: 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); 

kredyty przejść do: https://stackoverflow.com/a/7973554/2673005

+0

naprawdę nie chcę, aby móc ręcznie zmienić ramkę więc mogę zadzwonić do moich słuchaczy. Jeśli używam TransitionDrawable, nadal nie będę powiadamiany po każdej klatce. Dzięki za odpowiedź – laurentiugh

Powiązane problemy