SurfaceView可以说是View的孪生兄弟了,其实在Android系统提供的View就可以满足大部分的绘图需求了,但是在某些 时候,View也有些心有余而力不足。我们知道,View通过刷新来重回视图,android系统通过发出VSYNC信号进行视图的重 绘,刷新间隔为16ms,然后对于操作逻辑太多,需要频繁刷新页面(如:游戏界面)时,就会不断的阻塞主线程,从而导致页面 卡顿。为了避免这一问题,Android系统提供了SurfaceView组件来解决这一问题,下面一起来看一下SurfaceView的简单使用。
SurfaceView与View的区别主要体现在
- View主要适用于主动更新、刷新情况,SurfaceView主要适用于被动更新、刷新情况;
- View在绘制时没有适用双缓存机制,SurfaceView采用的双缓存机制;
SurfaceView的使用
SurfaceView的使用比View要复杂,但是在使用SurfaceView时,按照如下几部来使用,会让SurfaceView的使用更加简单。
1、创建SurfaceView
创建自定义的SurfaceView集成SurfaceView,并实现两个接口——SurfaceHolder.Callback、Runnable,代码如下所示:
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback,Runnable{
当然也可以通过内部类实现这两个接口。对于SurfaceHolder.Callback需要实现如下三个方法:
//创建
@Override
public void surfaceCreated(SurfaceHolder holder) {
}
//改变
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
//销毁
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
分别对应SurfaceView的创建、改变、销毁的过程。对于Runnable接口,需要实现run()。
2、初始化SurfaceView
在自定义的SurfaceView中,通常需要定义以下几个成员变量,代码如下:
private SurfaceHolder mHolder;//SurfaceHolder
private Canvas mCanvas;//用于绘制的Canvas
private boolean mIsDrawing;//子线程标志位
初始化方法就是对SurfaceHolder进行初始化,初始化一个SurfaceHolder对象,并注册SurfaceHolder的回调方法。Canvas与View的onDraw()方法中使用的Canvas一样,进行绘制用的。标志位则是用来控制子线程的,SurfaceView通常会起一个子线程来进行绘制,而这个标志位就可以可以子线程。
3、使用SurfaceView
通过SurfaceHolder对象的lockCanvas()方法,就可以获得当前的Canvas绘图对象。接下来,就可以与在View中进行绘制操作一样进行绘制了,获取到的Canvas对象还是继续上次的Canvas对象,因此,之前的绘图操作都将被保留,如果需要擦除,可以在绘制前调用drawColor()方法来进行清屏。绘制的时候,充分利用SurfaceView的三个回调方法,在surfaceCreated方法中开启子线程进行绘制,而子线程使用一个while(mIsDrawing)的循环来不停地进行绘制,而在绘制的具体逻辑中,通过lockCanvas()方法获取Canvas对象进行绘制,并通过unlockCanvasAndPost(mCanvas)方法对画布进行提交。整个SurfaceView的模版代码如下所示:
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback,Runnable{
private SurfaceHolder mHolder;//SurfaceHolder
private Canvas mCanvas;//用于绘制的Canvas
private boolean mIsDrawing;//子线程标志位
public MySurfaceView(Context context) {
super(context);
init();
}
public MySurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MySurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init(){
mHolder=getHolder();
mHolder.addCallback(this);
setFocusable(true);
setFocusableInTouchMode(true);
setKeepScreenOn(true);
}
//创建
@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();
//这里写要绘制的内容
}catch (Exception e){
}finally {
if(mCanvas!=null){
mHolder.unlockCanvasAndPost(mCanvas);//提交画布内容
}
}
}
}
标题例子——余弦曲线绘制
看一个类似示波器的例子,要绘制一个余弦曲线,只需要不断的修改横纵坐标的值,并让它们满足余弦函数即可。主要代码如下:
@Override
public void run() {
while(mIsDrawing){
draw();
x+=1;
y=(int)(100*Math.cos(x*2*Math.PI/180)+200);
mPath.lineTo(x,y);
}
}
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);//提交画布内容
}
}
}