我想通过更改 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();
}
});
有任何想法吗?:) 谢谢。