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…
关于清屏这块有没有有经验的小伙伴来评论区分享一下