SurfaceView的基础使用

SurfaceView

继承自View,拥有独立的绘图表面,即不与其宿主窗口共享一个绘图表面,通过Canvas画布绘制
可在另一线程中更新界面,且不阻碍界面交互,不会占用主线程资源

与View区别

SurfaceView
1、子线程中可以重新绘制画面,且绘图效率更高,适合动画等复杂绘制页面
2、每个SurfaceView拥有独立的surface,通过在顶级surface上打洞来显示自己。这些surface对应底层的Layer,由SurfaceFlinger根据这些layer的内容以及层级进行混合并最终显示
3、需通过SurfaceHolder.lockCanvas()主动获取canvas
4、一个SurfaceView拥有一个surface,它只需要对自己进行测量、布局和绘制。流程简单的多
5、实现重绘的方式更直观,每次主动调用doDraw()就是重新绘制
6、使用场景:主动更新画面的,如复杂的动画

View
1、必须在UI的主线程中更新画面
2、通过ViewRootImpl提供的顶级surface进行lockCanvas(Rect dirty),返回的canvas会在指定的dirty范围进行绘制
3、由顶级surface在ViewRootImple就已经lockCanvas后,把canvas传递到View的draw(canvas)
4、只拥有一个顶级surface,子view都是共用一个surface,所以在绘制时performTraversals()是对一个树结构的view群进行测量、布局、绘制的遍历
5、不能直接通过surface.lockCanvas获取canvas,只能通过调用invalidate()去触发父视图ViewRootImpl去调用performTraversal()去实现重绘
6、使用场景:被动更新画面的,如通过点击事件,来对画面进行重绘(invalidate())

Surface与Canvas区别

Surface
surfaceview可见部分,绘图操作(surfaceCreated/Changed/Destroyed,也是SurfaceHolder.Callback的回调,作用于内存区)作用于它
Canvas
绘制操作者,通过surface.lockCanvas(Rect dirty)获得,只能在dirty范围进行对surface指定区域的绘制

基础使用

//布局中放入SurfaceView控件
SurfaceView surfaceView=(SurfaceView)findViewById(R.id.surfaceview);
//获取SurfaceHolder
SurfaceHolder surfaceHolder=(SurfaceHolder) surfaceView.getHolder();
//实现SurfaceHolder.Callback方法
surfaceHolder.addCallback(new SurfaceHolder.Callback(){
	@Override public void surfaceDestroyed(SurfaceHolder holder) {}
	@Override public void surfaceCreated(SurfaceHolder holder){
		//获得canvas的大小并锁定canvas
		Canvas canvas=holder.lockCanvas();
		Bitmap bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
		canvas.drawBitmap(bitmap, 50, 50,new Paint());
		//提交更新canvas(可在子线程中进行)
		holder.unlockCanvasAndPost(canvas);
	}
	@Override public void surfaceChanged(SurfaceHolder holder,int format,int width,int height){}
});

问题

为什么可以使用子线程更新画面

view通过ViewRootImpl提供的surface作为顶级surface,所有的View均在其进行绘制
SurfaceView拥有自己独立的surface,由WindowManagerService完成绘制,并以在顶级surface上打洞的形式呈现

猜你喜欢

转载自blog.csdn.net/mLuoya/article/details/87829206