Android中SurfaceView的簡單使用

    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);//提交畫布內容
            }
        }
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章