在网上看过一些网友写的SurfaceView的原理啊,示例啊,对比了下View,我看到了SurfaceView的一些好处
- SurfaceView允许你在非ui线程中去绘制。
- SurfaceView的帧率可以操作60FPS
- 在要求实时性比较高的游戏开发中,显然,view的ondraw是满足不了你的,这时候只能是用SurfaceView。
下面是我写的一个自定义控件的demo:),因为模拟器录制不了视频,所以只能给出一个静态图,实际上的效果是,这个黄色的圆不断变大,文字像一个个字打上去的效果~~
其使用步骤和自定义View非常相似。
- 1、不同的是现在是继承自
SurfaceView
- 2、在初始化的时候,拿到
SurfaceHolder
,给SurfaceHolder
设置Callback
- 3、在
Callback
中去写几个回调方法surfaceCreated
,surfaceChanged
,surfaceDestroyed
。 - 4、在
surfaceCreated
中起一个线程,在线程中使用拿到的SurfaceHolder
去锁定Canvas
进行绘图。 - 5、在
surfaceDestroyed
中结束这个绘图线程。
基本的步骤其实就是以上5步,下面的是全部的自定义控件的实例代码,相关地方也写明的注释,相信很好理解
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执行完,上面的isRunning其实也达到这个目的咯
try {
mDrawThread.join();
} catch ( InterruptedException e ) {
e.printStackTrace();
}
}
///////////////////////////////////////////////////////////////////////////
// 这里的线程专门负责绘制
///////////////////////////////////////////////////////////////////////////
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);
//通过它来控制帧数执行一次绘制后休息500ms,实际上,我们知道,ondraw如果保证60FPS的话,看到的画面会比较流畅
//因此,这里,可能就是16ms咯,但是,我们这里完全可以设置的比16ms都小,知道surface的好处了吧。
Thread.sleep(500);
}
} catch ( InterruptedException e ) {
e.printStackTrace();
} finally {
surfaceHolder.unlockCanvasAndPost(c);
}
}
}
public void doDraw(Canvas c) {
//这个很重要,清屏操作,清楚掉上次绘制的残留图像,这里和view的ondraw不一样,view的ondraw每次执行之前,实际上会自动替你清除之前画的。
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;
}
}
}
}