view可以滿足大部分的繪圖需求,但是在某些時候卻心有餘而力不足,特别在是需要頻繁重新整理的界面上,例如遊戲界面,會不斷阻塞主線程,進而導緻畫面卡頓。這個時候我們就需要使用surfaceview了。
SurfaceView的使用
雖然說SurfaceView的使用比view複雜,但是在使用SurfaceView的時候會有一套使用的模版代碼,大部分的SurfaceView繪圖操作都可以套用這樣的模版代碼來進行編寫。是以SurfaceView的使用會更加簡單。
1.建立SurfaceView
建立自定義的SurfaceView繼承自SurfaceView,并實作兩個接口-SurfaceHolder.Callback和Runnable,具體代碼結尾展示,通過實作這兩個接口,就需要在自定義的SurfaceView中實作接口的方法
2.初始化SurfaceView
在SurfaceView的構造方法中,需要對SurfaceView進行初始化,通常需要定義三個成員變量。
SurfaceHolder,Canvas,線程标志位mIsDrawing
初始化SurfaceHolder對象,并注冊SurfaceHolder的回調方法。
mHolder=getHolder();
mHolder.addCallback(this);
如下時SurfaceView的一般套用模版
public class SurfaceViewTemplate extends SurfaceView
implements SurfaceHolder.Callback, Runnable {
// SurfaceHolder
private SurfaceHolder mHolder;
// 用于繪圖的Canvas
private Canvas mCanvas;
// 子線程标志位
private boolean mIsDrawing;
public SurfaceViewTemplate(Context context) {
super(context);
initView();
}
public SurfaceViewTemplate(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public SurfaceViewTemplate(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initView();
}
private void initView() {
mHolder = getHolder();
mHolder.addCallback(this);
setFocusable(true);
setFocusableInTouchMode(true);
this.setKeepScreenOn(true);
//mHolder.setFormat(PixelFormat.OPAQUE);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
mIsDrawing = true;
new Thread(this).start();
}
@Override
public void surfaceChanged(SurfaceHolder holder,
int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mIsDrawing = false;
}
@Override
public void run() {
while (mIsDrawing) {
draw();
}
}
private void draw() {
try {
mCanvas = mHolder.lockCanvas();
// draw sth
} catch (Exception e) {
} finally {
if (mCanvas != null)
mHolder.unlockCanvasAndPost(mCanvas);
}
}
}
下面是簡單畫闆實作
public class SimpleDraw extends SurfaceView
implements SurfaceHolder.Callback, Runnable {
private SurfaceHolder mHolder;
private Canvas mCanvas;
private boolean mIsDrawing;
private Path mPath;
private Paint mPaint;
public SimpleDraw(Context context) {
super(context);
initView();
}
public SimpleDraw(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public SimpleDraw(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
initView();
}
private void initView() {
mHolder = getHolder();
mHolder.addCallback(this);
setFocusable(true);
setFocusableInTouchMode(true);
this.setKeepScreenOn(true);
mPath = new Path();
mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(40);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
mIsDrawing = true;
new Thread(this).start();
}
@Override
public void surfaceChanged(SurfaceHolder holder,
int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mIsDrawing = false;
}
@Override
public void run() {
long start = System.currentTimeMillis();
while (mIsDrawing) {
draw();
}
long end = System.currentTimeMillis();
// 50 - 100優化部分,防止有時候繪制不那麼頻繁。
if (end - start < 100) {
try {
Thread.sleep(100 - (end - start));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void draw() {
try {
mCanvas = mHolder.lockCanvas();
mCanvas.drawColor(Color.WHITE);
mCanvas.drawPath(mPath, mPaint);
} catch (Exception e) {
} finally {
if (mCanvas != null)
mHolder.unlockCanvasAndPost(mCanvas);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mPath.moveTo(x, y);
break;
case MotionEvent.ACTION_MOVE:
mPath.lineTo(x, y);
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
}