1、自定义一个GIFView,通过Movie 显示动态的gif 图
public class GifView extends View {
private static final int DEFAULT_MOVIE_VIEW_DURATION = 1000;
private int mMovieResourceId;
private Movie movie;
private long mMovieStart;
private int mCurrentAnimationTime;
/**
* Position for drawing animation frames in the center of the view.
*/
private float mLeft;
private float mTop;
/**
* Scaling factor to fit the animation within view bounds.
*/
private float mScale;
/**
* Scaled movie frames width and height.
*/
private int mMeasuredMovieWidth;
private int mMeasuredMovieHeight;
private volatile boolean mPaused;
private boolean mVisible = true;
private IGifLoadFinishListener mIGifLoadFinishListener;
public interface IGifLoadFinishListener{
public void isLoadFinish();
}
public GifView(Context context) {
this(context, null);
}
public GifView(Context context, AttributeSet attrs) {
this(context, attrs, R.styleable.CustomTheme_gifViewStyle);
}
public GifView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setViewAttributes(context, attrs, defStyle);
}
@SuppressLint("NewApi")
private void setViewAttributes(Context context, AttributeSet attrs, int defStyle) {
/**
* Starting from HONEYCOMB(Api Level:11) have to turn off HW acceleration to draw
* Movie on Canvas.
*/
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
final TypedArray array = context.obtainStyledAttributes(attrs,
R.styleable.GifView, defStyle, R.style.Widget_GifView);
//-1 is default value
mMovieResourceId = array.getResourceId(R.styleable.GifView_gif, -1);
mPaused = array.getBoolean(R.styleable.GifView_paused, false);
array.recycle();
if (mMovieResourceId != -1) {
movie = Movie.decodeStream(getResources().openRawResource(mMovieResourceId));
}
}
public void setGifResource(int movieResourceId) {
this.mMovieResourceId = movieResourceId;
movie = Movie.decodeStream(getResources().openRawResource(mMovieResourceId));
mMovieStart = android.os.SystemClock.uptimeMillis();
requestLayout();
}
public void setGifResource(String path) {
movie = Movie.decodeFile(path);
mMovieStart = android.os.SystemClock.uptimeMillis();
requestLayout();
}
public int getGifResource() {
return this.mMovieResourceId;
}
public void play() {
if (this.mPaused) {
this.mPaused = false;
/**
* Calculate new movie start time, so that it resumes from the same
* frame.
*/
mMovieStart = android.os.SystemClock.uptimeMillis() - mCurrentAnimationTime;
invalidate();
}
}
public void pause() {
if (!this.mPaused) {
this.mPaused = true;
invalidate();
}
}
public boolean isPaused() {
return this.mPaused;
}
public boolean isPlaying() {
return !this.mPaused;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (movie != null) {
int movieWidth = movie.width();
int movieHeight = movie.height();
/*
* Calculate horizontal scaling
*/
float scaleH = 1f;
int measureModeWidth = MeasureSpec.getMode(widthMeasureSpec);
if (measureModeWidth != MeasureSpec.UNSPECIFIED) {
int maximumWidth = MeasureSpec.getSize(widthMeasureSpec);
if (movieWidth > maximumWidth) {
scaleH = (float) movieWidth / (float) maximumWidth;
}
}
/*
* calculate vertical scaling
*/
float scaleW = 1f;
int measureModeHeight = MeasureSpec.getMode(heightMeasureSpec);
if (measureModeHeight != MeasureSpec.UNSPECIFIED) {
int maximumHeight = MeasureSpec.getSize(heightMeasureSpec);
if (movieHeight > maximumHeight) {
scaleW = (float) movieHeight / (float) maximumHeight;
}
}
/*
* calculate overall scale
*/
mScale = 1f / Math.max(scaleH, scaleW);
mMeasuredMovieWidth = (int) (movieWidth * mScale);
mMeasuredMovieHeight = (int) (movieHeight * mScale);
setMeasuredDimension(mMeasuredMovieWidth, mMeasuredMovieHeight);
} else {
/*
* No movie set, just set minimum available size.
*/
setMeasuredDimension(getSuggestedMinimumWidth(), getSuggestedMinimumHeight());
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
/*
* Calculate mLeft / mTop for drawing in center
*/
mLeft = (getWidth() - mMeasuredMovieWidth) / 2f;
mTop = (getHeight() - mMeasuredMovieHeight) / 2f;
mVisible = getVisibility() == View.VISIBLE;
}
@Override
protected void onDraw(Canvas canvas) {
if (movie != null) {
if (!mPaused) {
updateAnimationTime();
//如果只需要要播放一次则加上if 这个条件,如果需要循环播放则,注释 if 条件即可
if (isFinish()) {
mCurrentAnimationTime = movie.duration();
drawMovieFrame(canvas);
if (mIGifLoadFinishListener != null){
mIGifLoadFinishListener.isLoadFinish();
}
return;
}
drawMovieFrame(canvas);
invalidateView();
} else {
drawMovieFrame(canvas);
}
}
}
/**
* Invalidates view only if it is mVisible.
*
* {@link #postInvalidateOnAnimation()} is used for Jelly Bean and higher.
*/
@SuppressLint("NewApi")
private void invalidateView() {
if (mVisible) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
postInvalidateOnAnimation();
} else {
invalidate();
}
}
}
/**
* Calculate current animation time
*/
private void updateAnimationTime() {
long now = android.os.SystemClock.uptimeMillis();
if (mMovieStart == 0) {
mMovieStart = now;
}
int dur = movie.duration();
if (dur == 0) {
dur = DEFAULT_MOVIE_VIEW_DURATION;
}
mCurrentAnimationTime = (int) ((now - mMovieStart) % dur);
}
/**
* Draw current GIF frame
*/
private void drawMovieFrame(Canvas canvas) {
movie.setTime(mCurrentAnimationTime);
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.scale(mScale, mScale);
movie.draw(canvas, mLeft / mScale, mTop / mScale);
canvas.restore();
}
@SuppressLint("NewApi")
@Override
public void onScreenStateChanged(int screenState) {
super.onScreenStateChanged(screenState);
mVisible = screenState == SCREEN_STATE_ON;
invalidateView();
}
@SuppressLint("NewApi")
@Override
protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
mVisible = visibility == View.VISIBLE;
invalidateView();
}
@Override
protected void onWindowVisibilityChanged(int visibility) {
super.onWindowVisibilityChanged(visibility);
mVisible = visibility == View.VISIBLE;
invalidateView();
}
/**
* 设置gif 加载完成事件监听
*/
public void setmIGifLoadFinishListener(IGifLoadFinishListener mIGifLoadFinishListener) {
this.mIGifLoadFinishListener = mIGifLoadFinishListener;
}
/**
* 判断是否播放到最后
*/
private boolean isFinish(){
long now = android.os.SystemClock.uptimeMillis();
return now- mMovieStart >=movie.duration();
}
}
2、在代码中使用
a、 xml 中直接使用
<***.GifView
android:id="@+id/gif1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
custom:gif="@mipmap/gif1" />
b、在代码中使用
GifView mGifView = (GifView) findViewById(R.id.gif1);
mGifView.setGifResource(R.drawable.ic_tab_find_normal);
//暂停
mGifView.pause();
//恢复
mGifView.play();
注意: GifView 里下面这段代码,是由于我项目中只需要播放一次,且只有一个地方用,如果不同地方对于播放是否循环不一致,可新增一个自定义属性,进行判断
if (isFinish()) {
mCurrentAnimationTime = movie.duration();
drawMovieFrame(canvas);
if (mIGifLoadFinishListener != null){
mIGifLoadFinishListener.isLoadFinish();
}
return;
}