gif動畫在web開發中使用的非常的多,利用gif,許多動畫不必再用程序編寫,現在有非常多的App已經使用到了gif動畫,可是android sdk並沒有爲我們提供gif這種View,所以我們只能自定義一個View,去實現gif效果.
android雖然沒有爲我們提供現成的GifView,但是爲我們提供了Movie類,這個類就是用來實現GifView的關鍵類.它主要有兩個最重要的方法,一個是根據動畫播放時間設置當前要現顯示的幀,二是將當前要顯示的幀繪製到畫布中.下面看一下效果圖:
點擊暫停按鈕還可以暫停gif動畫.
下面就看是如何實現的:
1.首先將需要用到的屬性先自定義好:如下代碼所示:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="gifCommon">
<attr name="gif_src" format="reference" />
<attr name="decode_stream" format="boolean" />
<attr name="default_animation_time" format="integer" />
</declare-styleable>
</resources>
三個屬性分別代表:gif資源,是否採用流編碼,默認動畫間隔時間.
2.自定義GifView代碼.
package view;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Movie;
import android.util.AttributeSet;
import android.view.View;
import com.example.drawbaledemo.R;
/**
* @author rzq
*
*/
public class GifView extends View {
private Movie mMovie;
/**
* 動畫開始時間
/
private long mMovieStart;
private boolean mPaused = false;
/**
* 當前幀動畫時間
/
private int mCurrentAnimationTime ;
/**
* 自定義的三個屬性
/
private boolean decode_STREAM;
private int src_ID;
private int default_time;
public GifView(Context context) {
super(context);
init(context, null);
}
public GifView(Context context, AttributeSet set) {
super(context, set);
init(context, set);
}
private void init(Context context, AttributeSet set) {
TypedArray a = context.obtainStyledAttributes(set,
R.styleable.gifCommon);
src_ID = a.getResourceId(R.styleable.gifCommon_gif_src, -1);
decode_STREAM = a.getBoolean(R.styleable.gifCommon_decode_stream, true);
default_time = a.getInteger(
R.styleable.gifCommon_default_animation_time, 1000);
a.recycle();
setFocusable(true);
java.io.InputStream is;
is = context.getResources().openRawResource(src_ID);
if (decode_STREAM) {
mMovie = Movie.decodeStream(is); // 根據文件流創建Movier繪製對象
} else {
byte[] array = streamToBytes(is);
mMovie = Movie.decodeByteArray(array, 0, array.length);
}
}
@Override
protected void onDraw(Canvas canvas) {
if (mMovie != null) {
if (!mPaused) {
// 更新幀時間
updateAnimationTime();
drawMovieFrame(canvas);
invalidate();
} else {
// 暫停時,不更新幀時間,則只畫當前幀
drawMovieFrame(canvas);
}
}
}
private void updateAnimationTime() {
long now = android.os.SystemClock.uptimeMillis();
// 如果第一幀,記錄起始時間
if (mMovieStart == 0) {
mMovieStart = now;
}
// 取出動畫的時長
int dur = mMovie.duration();
if (dur == 0) {
dur = default_time;
}
// 算出需要顯示第幾幀
mCurrentAnimationTime = (int) ((now - mMovieStart) % dur);
}
private void drawMovieFrame(Canvas canvas) {
// 設置要顯示的幀,繪製即可
mMovie.setTime(mCurrentAnimationTime);
canvas.save(Canvas.MATRIX_SAVE_FLAG);
mMovie.draw(canvas, 0, 0);
canvas.restore();
}
/**
* 設置暫停
*
* @param paused
*/
public void setPaused(boolean paused) {
this.mPaused = paused;
if (!paused) {
/**
* 更新動畫起點時間
*/
mMovieStart = android.os.SystemClock.uptimeMillis()
- mCurrentAnimationTime;
}
invalidate();
}
/**
* 判斷gif圖是否停止了
*
* @return
*/
public boolean isPaused() {
return this.mPaused;
}
/**
* 重寫此方法,使自定義View支持wrap_content
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width;
int height;
if (widthMode == MeasureSpec.EXACTLY) {
width = widthSize;
} else {
int desired = (int) (getPaddingLeft() + mMovie.width() + getPaddingRight());
width = Math.min(desired,widthSize);
}
if (heightMode == MeasureSpec.EXACTLY) {
height = heightSize;
} else {
int desired = (int) (getPaddingTop() + mMovie.height() + getPaddingBottom());
height = Math.min(desired,heightSize);
}
setMeasuredDimension(width, height);
}
/**
* 將流轉化爲字節數組
*
* @param is
* @return
*/
private static byte[] streamToBytes(InputStream is) {
ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
byte[] buffer = new byte[1024];
int len;
try {
while ((len = is.read(buffer)) >= 0) {
os.write(buffer, 0, len);
}
} catch (java.io.IOException e) {
}
return os.toByteArray();
}
}
3.佈局文件中使用GifView.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:gif="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#fed952"
android:gravity="center" >
<view.GifView
android:id="@+id/gif_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#ffffff"
gif:decode_stream="true"
gif:default_animation_time="1000"
gif:gif_src="@drawable/animated_gif" />
<TextView
android:id="@+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/gif_view"
android:text="暫停" />
</RelativeLayout>
與使用普通的View一樣,將需要的資源傳入即可.