SurfaceView 笔记

27 阅读2分钟

View和SurfaceView各自使用场景:

当界面需要被动更新时,用View较好。 当界面需要主动更新时,用SurfaceView较好。 当界面需要频繁刷新时,或者刷新数据处理量比较大时,用SurfaceView好。比如视频播放和摄像头。

setWillNotDraw(boolean flag)
//如果flag为true,则表示当前控件没有绘制内容,当屏幕重绘是这个控件不需要绘制。为false时,则表示当前控件在每次重绘时都需要绘制该控件,派生自SurfaceView 想要通过 onDraw实现绘制,就要设为false
public drawCanvas(){
    new Thread(new Runnable(){
         SurfaceHolder surfaceHolder = getHolder();
        Canvas canvas = surfaceHolder.lockCanvas();
        ...
        surfaceHolder.unlockCanvasAndPost(canvas);
    })
    
    //放到子线程里,不然和onDraw()方法没有区别,都是在主线程绘制
   

}


SurfaceHolder sh = getHolder();
    sh.addCallback(new 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) {
        
        }
    
    });
    //防止画布被其他锁定或者缓存Canvas没有被创建,进行监听。

lockCanvas(Rect rect) rect内的区域内是我们要绘制的,rect是复制屏幕外的,这个怎么理解,我们知道是有双缓冲或者三缓冲的。比如A,B,C三个缓冲,而缓冲遵循lRU策略,我们在绘制ABC完后,重新启用A进行绘制,那复制的屏幕外就是之前A上已经绘制存在的东西。为了防止之前已经缓存的内容对先内容造成污染,所以我们需要先清空一下画布。

While(true){
   Rect dirtyRect = new Rect(0,0,1,1);
   Canvas  canvas = holder.lockCanvas(dirtyRect);
   Rect canvasRect = canvas.getClipBounds();
       if(getWidth() == canvasRect.width() && getHeight() == canvasRect.height()){
           canvas.drawColor(Color.BLACK);
           holder.unlockCanvasAndPost(canvas);
       }else{
            holder.unlockCanvasAndPost(canvas);
       }
}
//Paint paint = new Paint();
//paint.setXfermode(new PosterDuffXfermode(PorterDuff.Mode.Clear))
//canvas.drawPaint(paint);
Paint clearPaint = new Paint();  
clearPaint.setAntiAlias(true);  
clearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));

mDrawingView.mCanvas.drawRect(0, 0, 800, 480, clearPaint);  
Canvas canvas = mDrawingView.mSurfaceHolder.lockCanvas();  
canvas.drawColor(Color.TRANSPARENT,Mode.CLEAR);  
canvas.drawBitmap(mDrawingView.mBitmap, 0, 0, mDrawingView.mBitmapPaint);  
mDrawingView.mSurfaceHolder.unlockCanvasAndPost(canvas);

canvas = getHolder.lockCanvas(null);
if(canvas != null){
    canvas.drawColor(Color.TRANSPARENT);

    //绘制内容
    getHolder().unlockCanvasAndPost(canvas);

}

插个眼: 网上有说法说如果是视频的话,用lock 和 unlockcanvas会有问题

stackoverflow.com/questions/2…

建议使用GlES来清屏

import android.opengl.EGL14;
import android.opengl.EGLConfig;
import android.opengl.EGLContext;
import android.opengl.EGLDisplay;
import android.opengl.EGLExt;
import android.opengl.EGLSurface;
import android.opengl.GLES20;

//=====

/**
* Clears the playback surface to black.
*/
private void clearSurface(Surface surface) {
   EGLDisplay display = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
   int[] version = new int[2];
   EGL14.eglInitialize(display, version, 0, version, 1);

   int[] attribList = {
           EGL14.EGL_RED_SIZE, 8,
           EGL14.EGL_GREEN_SIZE, 8,
           EGL14.EGL_BLUE_SIZE, 8,
           EGL14.EGL_ALPHA_SIZE, 8,
           EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
           EGL14.EGL_NONE, 0,
           EGL14.EGL_NONE
   };
   EGLConfig[] configs = new EGLConfig[1];
   int[] numConfigs = new int[1];
   EGL14.eglChooseConfig(display, attribList, 0, configs, 0, configs.length, numConfigs, 0);

   EGLConfig config = configs[0];
   EGLContext context = EGL14.eglCreateContext(display, config, EGL14.EGL_NO_CONTEXT, new int[]{
           EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
           EGL14.EGL_NONE
   }, 0);

   EGLSurface eglSurface = EGL14.eglCreateWindowSurface(display, config, surface,
           new int[]{
               EGL14.EGL_NONE
           }, 0);

   EGL14.eglMakeCurrent(display, eglSurface, eglSurface, context);
   GLES20.glClearColor(0, 0, 0, 1);
   GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
   EGL14.eglSwapBuffers(display, eglSurface);
   EGL14.eglDestroySurface(display, eglSurface);
   EGL14.eglMakeCurrent(display, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT);
   EGL14.eglDestroyContext(display, context);
   EGL14.eglTerminate(display);
}


stackoverflow.com/questions/2…

关于清屏这块有没有有经验的小伙伴来评论区分享一下