SurfaceView是视图(View)的继承类,这个视图里内嵌了一个专门用于绘制的Surface。你可以控制这个Surface的格式和尺寸。Surfaceview控制这个Surface的绘制位置。
surface是纵深排序(Z-ordered)的,这表明它总在自己所在窗口的后面。surfaceview提供了一个可见区域,只有在这个可见区域内的surface部分内容才可见,可见区域外的部分不可见。surface的排版显示受到视图层级关系的影响,它的兄弟视图结点会在顶端显示。这意味者 surface的内容会被它的兄弟视图遮挡,这一特性可以用来放置遮盖物(overlays)(例如,文本和按钮等控件)。注意,如果surface上面有透明控件,那么它的每次变化都会引起框架重新计算它和顶层控件的透明效果,这会影响性能。
你可以通过SurfaceHolder接口访问这个surface,getHolder()方法可以得到这个接口。surfaceview变得可见时,surface被创建;surfaceview隐藏前,surface被销毁。这样能节省资源。如果你要查看 surface被创建和销毁的时机,可以重载surfaceCreated(SurfaceHolder)和 surfaceDestroyed(SurfaceHolder)。
surfaceview的核心在于提供了两个线程:UI线程和渲染线程。这里应注意:
1>所有SurfaceView和SurfaceHolder.Callback的方法都应该在UI线程里调用,一般来说就是应用程序主线程。渲染线程所要访问的各种变量应该作同步处理。
2>由于surface可能被销毁,它只在SurfaceHolder.Callback.surfaceCreated()和 SurfaceHolder.Callback.surfaceDestroyed()之间有效,所以要确保渲染线程访问的是合法有效的surface。
注:摘自http://www.cnblogs.com/xuling/archive/2011/06/06/android.html
接下来我们定义一个MySurfaceView类,用来实现拖动文本的效果。但是我们希望通过不停的定时刷新界面来达到我们想要的效果。
首先我们继承自SurfaceView,并实现android.view.SurfaceHolder.Callback接口。因为我们想不停的定时刷新界面所以这里也需要实现Runnable。
重写run()函数、surfaceCreated()函数、surfaceChanged()函数、surfaceDestroyed()函数、onTouchEvent()函数。
代码如下:
publicclass MySurfaceView extends SurfaceView implements Callback,Runnable{
private String tag = "MySurfaceView";
private SurfaceHolder surfaceHolder;
private Paint paint;
privateinttextX = 10,textY = 10;
private Thread mThread;
privatebooleanflag;//线程标识位
private Canvas canvas;
public MySurfaceView ( Context context )
{
super(context) ;
Log.d(tag, "MySurfaceView");
surfaceHolder = this.getHolder();
//一定要有addCallback()函数,没有则响应不了监听
surfaceHolder.addCallback(this);
paint = new Paint();
paint.setColor(Color.WHITE);
setFocusable(true);
}
@Override
publicvoid run()
{
while(flag){
Log.d(tag, "thread is run");
long start = System.currentTimeMillis();
myDraw();//绘图
long end = System.currentTimeMillis();
if(end - start < 50){
try
{
Thread.sleep(50 -(end - start));
}
catch ( InterruptedException e )
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
@Override
publicvoid surfaceCreated(SurfaceHolder holder)
{
// TODO Auto-generated method stub
Log.d(tag, "surfaceCreated");
flag = true;
mThread = new Thread(this);
mThread.start();
}
@Override
publicvoid surfaceChanged(SurfaceHolder holder, int format, int width, int height)
{
Log.d(tag, "surfaceChanged");
// TODO Auto-generated method stub
}
@Override
publicvoid surfaceDestroyed(SurfaceHolder holder)
{
Log.d(tag, "surfaceDestroyed");
flag = false;
}
publicvoid myDraw(){
Log.d(tag, "myDraw");
canvas = surfaceHolder.lockCanvas();
if(canvas != null){
Log.d(tag, "canvas is not null");
//每次绘画都给画布重新上色以覆盖上一次绘画的文本----刷屏
canvas.drawRGB(0, 0, 0);
canvas.drawText("GAME", textX, textY, paint);
surfaceHolder.unlockCanvasAndPost(canvas);
}else{
Log.d(tag, "canvas is null");
}
}
@Override
publicboolean onTouchEvent(MotionEvent event)
{
Log.d(tag,"onTouchEvent");
//获取滑动的坐标
textX = ( int ) event.getX();
textY = ( int ) event.getY();
returntrue ;
}
}
其实刷屏方式不止代码中用到的一种方法,还有以下三种:
1)、每次绘图都绘制一个等同于屏幕大小的图形覆盖在画布上。
publicvoid myDraw(){
Log.d(tag, "myDraw");
canvas = surfaceHolder.lockCanvas();
if(canvas != null){
Log.d(tag, "canvas is not null");
//每次绘画都给画布重新上色以覆盖上一次绘画的文本----刷屏
canvas.drawRect(0,0,this.getWith(),this.getHeight(),paint);
Paint paintText = new Paint();
paintText.setColor(Color.WHITE);
canvas.drawText("GAME", textX, textY, paintText);
surfaceHolder.unlockCanvasAndPost(canvas);
}else{
Log.d(tag, "canvas is null");
}
}
2)、每次绘图之前,在画布上填充一种颜色。
publicvoid myDraw(){
Log.d(tag, "myDraw");
canvas = surfaceHolder.lockCanvas();
if(canvas != null){
Log.d(tag, "canvas is not null");
//每次绘画都给画布重新上色以覆盖上一次绘画的文本----刷屏
canvas.drawColor(Color.BLACK);
canvas.drawText("GAME", textX, textY, paint);
surfaceHolder.unlockCanvasAndPost(canvas);
}else{
Log.d(tag, "canvas is null");
}
}
3)、每次绘图之前,绘制一张等同于屏幕大小的图片覆盖在画布上。
其实不管那种方法其原理都是在绘制画布之前对画布进行一次整体覆盖。就像小时候喜欢在书页角上画走动的小人一样,每翻过一页都将上一页覆盖掉,速度快了看起来就连贯了,其实这也是动画的原理。