在網(wǎng)上看過一些網(wǎng)友寫的SurfaceView的原理啊笙隙,示例啊趾娃,對比了下View默终,我看到了SurfaceView的一些好處
- SurfaceView允許你在非ui線程中去繪制。
- SurfaceView的幀率可以操作60FPS
- 在要求實時性比較高的游戲開發(fā)中,顯然降狠,view的ondraw是滿足不了你的磷杏,這時候只能是用SurfaceView溜畅。
下面是我寫的一個自定義控件的demo:),因為模擬器錄制不了視頻极祸,所以只能給出一個靜態(tài)圖慈格,實際上的效果是,這個黃色的圓不斷變大遥金,文字像一個個字打上去的效果~~
其使用步驟和自定義View非常相似浴捆。
- 1、不同的是現(xiàn)在是繼承自
SurfaceView
- 2稿械、在初始化的時候选泻,拿到
SurfaceHolder
,給SurfaceHolder
設(shè)置Callback
- 3、在
Callback
中去寫幾個回調(diào)方法surfaceCreated
,surfaceChanged
,surfaceDestroyed
页眯。 - 4梯捕、在
surfaceCreated
中起一個線程,在線程中使用拿到的SurfaceHolder
去鎖定Canvas
進(jìn)行繪圖窝撵。 - 5傀顾、在
surfaceDestroyed
中結(jié)束這個繪圖線程。
基本的步驟其實就是以上5步碌奉,下面的是全部的自定義控件的實例代碼短曾,相關(guān)地方也寫明的注釋,相信很好理解
package test.tencent.com.test;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
/**
* Created by brzhang on 16/7/16.
* Description :
*/
public class DrawView extends SurfaceView implements SurfaceHolder.Callback {
private int mWidth;
private int mHeight;
private DrawThread mDrawThread;
public DrawView(Context context) {
this(context, null);
}
public DrawView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DrawView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initView();
}
private void initView() {
SurfaceHolder holder = getHolder();
holder.addCallback(this);
mDrawThread = new DrawThread(holder);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = getMeasuredWidth();
mHeight = getMeasuredHeight();
}
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
mDrawThread.isRunning = true;
mDrawThread.start();
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
mDrawThread.isRunning = false;
//這塊的意思其實就是赐劣,等待DrawThread執(zhí)行完嫉拐,上面的isRunning其實也達(dá)到這個目的咯
try {
mDrawThread.join();
} catch ( InterruptedException e ) {
e.printStackTrace();
}
}
///////////////////////////////////////////////////////////////////////////
// 這里的線程專門負(fù)責(zé)繪制
///////////////////////////////////////////////////////////////////////////
class DrawThread extends Thread {
SurfaceHolder surfaceHolder;
boolean isRunning;
int radius = 10;
Paint mPaintCirlce;
Paint mPaintText;
public DrawThread(SurfaceHolder surfaceHolder) {
this.surfaceHolder = surfaceHolder;
isRunning = false;
mPaintCirlce = new Paint();
mPaintCirlce.setStrokeWidth(4);
mPaintCirlce.setColor(Color.YELLOW);
mPaintCirlce.setStyle(Paint.Style.FILL_AND_STROKE);
mPaintText = new Paint();
mPaintText.setTextSize(24);
}
@Override
public void run() {
Canvas c = null;
while (isRunning) {
try {
synchronized (surfaceHolder) {
c = surfaceHolder.lockCanvas(null);
doDraw(c);
//通過它來控制幀數(shù)執(zhí)行一次繪制后休息500ms,實際上,我們知道魁兼,ondraw如果保證60FPS的話婉徘,看到的畫面會比較流暢
//因此,這里璃赡,可能就是16ms咯判哥,但是,我們這里完全可以設(shè)置的比16ms都小碉考,知道surface的好處了吧塌计。
Thread.sleep(500);
}
} catch ( InterruptedException e ) {
e.printStackTrace();
} finally {
surfaceHolder.unlockCanvasAndPost(c);
}
}
}
public void doDraw(Canvas c) {
//這個很重要,清屏操作侯谁,清楚掉上次繪制的殘留圖像锌仅,這里和view的ondraw不一樣,view的ondraw每次執(zhí)行之前墙贱,實際上會自動替你清除之前畫的热芹。
c.drawColor(Color.WHITE);
c.translate(mWidth / 2, mHeight / 2); //這里將畫筆放到view的中間
c.drawCircle(0, 0, radius++, mPaintCirlce);
String text = "這里是surface測試ooo";
c.drawText(text.substring(0,radius % text.length()+1), -mPaintText.measureText(text.substring(0,radius % text.length()+1)) / 2, 0f, mPaintText);
if (radius > mWidth / 2) {
radius = 10;
}
}
}
}