SurfaceView是使用的双缓冲机制,所以在性能上面是比view更优越的类,在使用SurfaceView的时候其实并不是和SurfaceView直接打交道,而是通过SurfaceHolder的实例来控制SurfaceView的大小和格式等,并且主要用于监听surfaceview的状态,获取canvas对象的方式即通过surfaceholder的lockcanvas()方法锁定画布,并且返回一个canvas,然后就可以在获得的画布上面大展手脚了!!!当绘制完毕的时候通过surfaceholder的unloccanvasandpost();方法即可解锁画布,并且提交。
当对surfaceview进行监听的时候必须实现surfaceholder的callback接口即必须重写三个函数:surfacechanged、surfacecreated、surfacedestroyed最后通过surfaceholder类的addcallback(Callback callback);方法将其监听借口实例传入,即可完成对surfaceView的监听。以下是一个小的demo:
MSurfaceView.java
public class MSurfaceView extends SurfaceView implements Callback{ private Paint paint; private SurfaceHolder holder; private int x, y; private int radius; public MSurfaceView(Context context){ super(context); // TODO Auto-generated constructor stub paint = new Paint(); holder = this.getHolder(); holder.addCallback(this); paint.setColor(Color.RED); } @Override public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) { // TODO Auto-generated method stub //mDraw(); } @Override public void surfaceCreated(SurfaceHolder arg0) { // TODO Auto-generated method stub } @Override public void surfaceDestroyed(SurfaceHolder arg0) { // TODO Auto-generated method stub } public void mDraw(){ Canvas canvas = holder.lockCanvas(); canvas.drawText("HELLO SURFACEVIEW", x, y, paint); canvas.drawCircle(x, y, setRadius(), paint); holder.unlockCanvasAndPost(canvas); } private int setRadius(){ radius = (int)(Math.random()*20); return radius; } @Override public boolean onTouchEvent(MotionEvent event) { // TODO Auto-generated method stub x = (int)event.getX(); y = (int)event.getY(); mDraw(); return true; } }
在Mainactivity.java文件里面将surfaceView作为当前显示的view:
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(new MSurfaceView(this)); } }
运行效果如下:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
现在实现通过自定义一个线程来绘制surfaceview,线程的定义通过implements Runnable接口来完成,代码做如下修改:
public class MSurfaceView extends SurfaceView implements Callback, Runnable{ private Paint paint; private SurfaceHolder holder; private int x, y; private int radius; private Thread mThread; private boolean threadstate; public MSurfaceView(Context context){ super(context); // TODO Auto-generated constructor stub paint = new Paint(); holder = this.getHolder(); holder.addCallback(this); paint.setColor(Color.RED); setFocusable(true); } @Override public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) { // TODO Auto-generated method stub //mDraw(); } @Override public void surfaceCreated(SurfaceHolder arg0) { // TODO Auto-generated method stub threadstate = true; mThread = new Thread(this); mThread.start(); } @Override public void surfaceDestroyed(SurfaceHolder arg0) { // TODO Auto-generated method stub threadstate = false; } public void mDraw(){ Canvas canvas = holder.lockCanvas(); if (canvas != null) { canvas.drawRGB(0, 0, 0); canvas.drawText("HELLO SURFACEVIEW", x, y, paint); canvas.drawCircle(x, y, setRadius(), paint); } holder.unlockCanvasAndPost(canvas); } private int setRadius(){ radius = (int)(Math.random()*20); return radius; } @Override public boolean onTouchEvent(MotionEvent event) { // TODO Auto-generated method stub x = (int)event.getX(); y = (int)event.getY(); // mDraw(); return true; } @Override public void run() { int X = 500; // TODO Auto-generated method stub while(threadstate){ long start = System.currentTimeMillis(); mDraw(); long end = System.currentTimeMillis(); try { if ((end - start) < X) { Thread.sleep(X - (end - start)); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
其中的setradius()方法是简单的实现了为绘制的园随机取半径大小,而这句代码:canvas.drawRGB(0,0,0);的作用即覆盖画布,意思就是在第一次画的东西上面重新设置了画布的颜色用以把第一次画的东西覆盖掉,这样看起来就有了刷屏的效果了,还有其他几种“刷屏”的方式:
1.每次回执之前先绘制一个与屏幕大小相等的图形覆盖在屏幕上面;
2.每次绘制之前重新绘制屏幕的颜色,即绘制画布的颜色;
3.~~~~~~指定RGB来填充canvas(本例的做法);
4.~~~~~绘制一张背景图片,很多游戏场景就是这么做的;
其实实现原理都是一样,即想办法覆盖掉原来的东西MainAcitivity.java的代码没有改变。
运行效果如下: