SurfaceView在遊戲開發中占著舉足輕重的地位。今天好好找資料看瞭看。附帶自己寫的例子。
寫變化不太快的畫面時,用View就足夠瞭,用View寫太快的畫面變化時,可能會出現屏幕閃爍。當寫如像植物大戰僵屍、水果忍者等遊戲時,用View就不能滿足要求瞭。Android提供瞭SurfaceView,它是專門用來做動畫,它是View的子類。
在SurfaceView自帶2級緩存,當寫變換比較快的遊戲時,二級緩存會讓遊戲畫面的變化看起來比較連貫一些。2級緩存的作用就是提前把將要繪制的圖片放到內存裡面。
一、實現最基本的SurfaceView隻需基礎即可,再按4個步驟來做即可。直接上代碼,詳細看代碼裡裡面的註釋。
[java]
public class GameView extends SurfaceView
{
SurfaceHolder surfaceHolder;
public GameView(Context context)
{
super(context);
//1. 獲得SurfaceView下是SurfaceHolder, surfaceHolder相當於一個遙控器來控制SurfaceView
surfaceHolder = this.getHolder();
//這個是回調方法, 必須有. 否則會報空指針異常. 意思是surface創建, 銷毀,改變
surfaceHolder.addCallback(new Callback()
{
@Override
public void surfaceDestroyed(SurfaceHolder holder)
{
}
@Override
public void surfaceCreated(SurfaceHolder holder)
{
//2. 在surface創建後鎖定畫佈
Canvas canvas = surfaceHolder.lockCanvas();
//3. 可以在畫佈上進行任意的繪畫操作( 下面是畫一條紅色 的線 )
Paint paint = new Paint();
paint.setColor(Color.RED);
canvas.drawLine(0, 0, 100, 100, paint);
//4. 將畫佈解鎖並顯示在屏幕上
surfaceHolder.unlockCanvasAndPost(canvas);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height)
{
}
});
}
當然,這樣寫很明顯不是最好的。隻有SurfaceView很明顯不能實現動畫,當然要與線程結合起來。用線程來刷屏。
二、使用SurfaceView來寫動畫的一般寫法。直接上代碼,詳細解釋請看代碼裡裡面的註釋。
[java]
public class GameViewOK extends SurfaceView implements Callback, Runnable
{
SurfaceHolder surfaceHolder;
private boolean isThreadRunning = true;
Canvas canvas;
float r = 10;
public GameViewOK(Context context)
{
super(context);
surfaceHolder = this.getHolder();
surfaceHolder.addCallback(this);//註冊回調方法
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height)
{
}
@Override
public void surfaceCreated(SurfaceHolder holder)
{
//創建surfaceView時啟動線程
new Thread(this).start();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder)
{
//當surfaceView銷毀時, 停止線程的運行. 避免surfaceView銷毀瞭線程還在運行而報錯.
isThreadRunning = false;
//第三種方法防止退出時異常. 當surfaceView銷毀時讓線程暫停300ms . 醒來再執行run()方法時,isThreadRunning就是false瞭.
try
{
Thread.sleep(300);
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
/**
* 將繪圖的方法單獨寫到這個方法裡面.
*/
private void drawVieW()
{
try
{//第一種方法防止退出時異常: 當isThreadRunning為false時, 最後還是會執行一次drawView方法, 但此時surfaceView已經銷毀
//因此才來判斷surfaceHolder
if (surfaceHolder != null)
{
//1. 在surface創建後鎖定畫佈
canvas = surfaceHolder.lockCanvas();
//2. 可以在畫佈上進行任意的繪畫操作( 下面是畫一條紅色 的線 )
Paint paint = new Paint();
paint.setColor(Color.BLUE);
//paint.setStyle(Style.STROKE);//隻有邊框
paint.setStrokeWidth(5);
canvas.drawCircle(100, 100, r++, paint);
}
} catch (Exception e)
{
e.printStackTrace();
} finally
{
//canvas是根據surfaceHolder得到的, 最後一次surfaceView已經銷毀, canvas當然也不存在瞭.
if (canvas != null)
//3. 將畫佈解鎖並顯示在屏幕上
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
@Override
public void run()
{
//每隔100ms刷新屏幕
while (isThreadRunning)
{
drawVieW();
try
{
Thread.sleep(100);
} catch (Exception e)
{
e.printStackTrace();
}
}
}
/*
* 這個是第二種方法解決退出是報錯的問題. 當按下返回鍵時, 提前設置isThreadRunning為false, 讓線程結束.
@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if(keyCode == KeyEvent.KEYCODE_BACK)
{
isThreadRunning = false;
}
return super.onKeyDown(keyCode, event);
}
*/
}
運行效果:不斷增大的圓形