之前我們對view和surfaceview 做了比較和取捨,最後我們發現surfaceview更加的適合運作與遊戲開發中,那麼下面就讓我們來看看這個surfaceview的結構吧;
package eoe.demo;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.SurfaceHolder.Callback;
import android.view.animation.Animation;
/**
* @author Himi
*/
public class MySurfaceView extends SurfaceView implements Callback, Runnable {// 備忘1
private SurfaceHolder sfh;
private Thread th;
private Canvas canvas;
private Paint paint;
private int ScreenW, ScreenH;
public MySurfaceView(Context context) {
super(context);
th = new Thread(this);
sfh = this.getHolder();
sfh.addCallback(this); // 備忘1
paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.RED);
this.setKeepScreenOn(true);// 保持螢幕常亮
}
@Override
public void startAnimation(Animation animation) {
super.startAnimation(animation);
}
public void surfaceCreated(SurfaceHolder holder) {
ScreenW = this.getWidth();// 備忘2
ScreenH = this.getHeight();
th.start();
}
private void draw() {
try {
canvas = sfh.lockCanvas(); // 得到一個canvas執行個體
canvas.drawColor(Color.WHITE);// 刷屏
canvas.drawText("Himi", 100, 100, paint);// 畫文字文本
canvas.drawText("這就是簡單的一個遊戲架構", 100, 130, paint);
} catch (Exception ex) {
} finally { // 備忘3
if (canvas != null)
sfh.unlockCanvasAndPost(canvas); // 將畫好的畫布提交
}
}
public void run() {
while (true) {
draw();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
}
代碼很簡單,我們繼承繼承surfaceview類,並且使用回調callback介面以及線程runnable介面。那麼這裡我簡單的說下Callback介面和SurfaceHolder 類的作用;
//備忘1
callback介面:
只要繼承SurfaceView類並實現SurfaceHolder.Callback介面就可以實現一個自訂的SurfaceView了,SurfaceHolder.Callback在底層的Surface狀態發生變化的時候通知View,SurfaceHolder.Callback具有如下的介面:
surfaceCreated(SurfaceHolder holder):當Surface第一次建立後會立即調用該函數。程式可以在該函數中做些和繪製介面相關的初始化工作,一般情況下都是在另外的線程來繪製介面,所以不要在這個函數中繪製Surface。
surfaceChanged(SurfaceHolder holder, int format, int width,int height):當Surface的狀態(大小和格式)發生變化的時候會調用該函數,在surfaceCreated調用後該函數至少會被調用一次。
SurfaceHolder 類:
它是一個用於控制surface的介面,它提供了控制surface 的大小,格式,上面的像素,即監視其改變的。
SurfaceView的getHolder()函數可以擷取SurfaceHolder對象,Surface 就在SurfaceHolder對象內。雖然Surface儲存了當前視窗的像素資料,但是在使用過程中是不直接和Surface打交道的,由SurfaceHolder的Canvas lockCanvas()或則Canvas lockCanvas()函數來擷取Canvas對象,通過在Canvas上繪製內容來修改Surface中的資料。如果Surface不可編輯或則尚未建立調用該函數會返回null,在 unlockCanvas() 和 lockCanvas()中Surface的內容是不緩衝的,所以需要完全重繪Surface的內容,為了提高效率只重繪變化的部分則可以調用lockCanvas(Rect rect)函數來指定一個rect地區,這樣該地區外的內容會緩衝起來。在調用lockCanvas函數擷取Canvas後,SurfaceView會擷取Surface的一個同步鎖直到調用unlockCanvasAndPost(Canvas canvas)函數才釋放該鎖,這裡的同步機制保證在Surface繪製過程中不會被改變(被摧毀、修改)。
//備忘2
我沒有在該surfaceview的初始化函數中將其 ScreenW 與 ScreenH 進行賦值,這裡要特別注意,如果你在初始化調用ScreenW = this.getWidth();和ScreenH = this.getHeight();那麼你將得到很失望的值 全部為0;原因是和介面Callback介面機制有關,當我們繼承callback介面會重寫它的surfaceChanged()、surfaceCreated()、surfaceDestroyed(),這幾個函數當surfaceCreated()被執行的時候,真正的view才被建立,也就是說之前得到的值為0 ,是因為初始化會在surfaceCreated()方法執行以前執行,view沒有的時候我們去取螢幕寬高肯定是0,所以這裡要注意這一點;
//備忘3
這裡我把draw的代碼都try起來,主要是為了當畫的內容中一旦拋出異常了,那麼我們也能 在finally中執行該操作。這樣當代碼拋出異常的時候不會導致Surface出去不一致的狀態。