欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android中SurfaceView的简单使用

程序员文章站 2022-03-30 14:13:03
...

    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);//提交画布内容
            }
        }
    }