Android SurfaceView 是Android系統(tǒng)中的高級(jí)組件飒房,它有自己的繪制界面赢织,可以在一個(gè)獨(dú)立的線程進(jìn)行UI的繪制擎鸠,因此不會(huì)阻塞主線程揭鳞,這也是我們使用SuefaceView播放gif圖片的原因炕贵。
先簡(jiǎn)單說一下思路,gif圖其實(shí)就是由一幀一幀的圖片組成野崇,當(dāng)我們想要播放gif的時(shí)候称开,其實(shí)就是播放gif的每一幀,這樣我們只需要解決以下就可以實(shí)現(xiàn)gif的播放:
1.gif一共有多少幀乓梨;
2.隨時(shí)間的推移尋找對(duì)應(yīng)的那一幀鳖轰;
3.播放該幀.
Android中有一個(gè)Moive類,這個(gè)類中提供的方法可以很好的解決這三個(gè)問題. movie.duration() 可以獲取一共有多少幀扶镀, movie.setTime()顯示哪一幀蕴侣。
代碼如下(有注釋):
public class GifSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder holder;
private String path = "test.gif";
private Movie movie;
// 縮放系數(shù)
private float zoom = 2;
// 執(zhí)行 gif動(dòng)畫
private Handler handler = new Handler();
private Runnable runnable ;
public GifSurfaceView(Context context) {
super(context);
initData();
}
public GifSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
initData();
}
public GifSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initData();
}
private void initData() {
runnable= new Runnable() {
@Override
public void run() {
// gif動(dòng)畫 是由一幀 的圖片組成,實(shí)現(xiàn) gif動(dòng)畫就是將 一幀幀的圖 畫出來狈惫,
// 首先獲取畫布
Canvas canvas = holder.lockCanvas();
// 保存當(dāng)前畫布狀態(tài)(此處保存畫布狀態(tài) 是為了保證 不影響下一幀的 縮放---下方 有 恢復(fù)狀態(tài))
canvas.save();
canvas.scale(zoom, zoom);
//設(shè)置畫布
movie.draw(canvas, 0, 0);
//逐幀繪制圖片
//這里使用時(shí)間戳 與總幀數(shù) 求余操作睛蛛,這樣 隨著時(shí)間的推移計(jì)算出該播放哪一幀
movie.setTime((int) (System.currentTimeMillis() % movie.duration()));
// 恢復(fù)之前保存的狀態(tài)
canvas.restore();
holder.unlockCanvasAndPost(canvas);
// 循環(huán)執(zhí)行
handler.postDelayed(runnable, 50);
}
};
holder = getHolder();
holder.addCallback(this);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
/**
* 測(cè)量組件,設(shè)置 組件的寬高
* 之所以 將Moive 的初始化放在這里是因?yàn)閟urfaceView再 默認(rèn)情況下是填充滿 父組件的
* 設(shè)置SurfaceView的寬高 和gif寬高保持一致
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// surfaceView 默認(rèn)情況下 填充滿 父組件
//加載gif圖片
try {
InputStream open = getContext().getAssets().open(path);
// 使用影片對(duì)象 處理gif圖片
movie = Movie.decodeStream(open);
// 獲取 move對(duì)象的寬高(實(shí)際為gif 的寬高)
int width = movie.width();
int height = movie.height();
// 設(shè)置surfaceView組件的寬高 使其保持 和 gif圖的寬高一致
setMeasuredDimension((int) (width * zoom), (int) (height * zoom));
} catch (IOException e) {
}
}
public float getZoom() {
return zoom;
}
public void setZoom(float zoom) {
this.zoom = zoom;
}
// 開始執(zhí)行g(shù)if動(dòng)畫
public void start() {
handler.post(runnable);
}
// 開始執(zhí)行g(shù)if動(dòng)畫
public void stop() {
handler.removeCallbacks(runnable);
}
}