SurfaceView
android开发者网站:
https://developer.android.com/reference/android/view/SurfaceView
中文网站
https://developer.android.com/guide/topics/media/media-formats
SurfaceView简介
SurfaceView是android系统中特殊的视图,继承自View。它具有独立的绘图表面;
由于其绘图surface的z轴位置在它所属的窗口的后面,因此,为了使其可见,SurfaceView在其宿主窗口上挖个洞来显示它的surface。
一切条件就绪后,就可以在独立的线程中进行复杂的UI绘制,且不会影响应用程序的主线程响应用户输入。
1.当SurfaceView被设置为不可见的时候,其所对应的Surface就会销毁,再想去显示这个SurfaceView的时候就不得不重新创建;
2.SurfaceView的背景层次比其描画的内容(Surface)高,因此SurfaceView设置背景后,要调用setZOrderOnTop(true)这个方法才能把我们的内容画上,
要不然我们所绘制的内容就在背景后面了,被背景覆盖。
可以使用SurfaceHolder的接口获取surface,SurfaceView调用getHolder()
通过实现SurfaceHolder.Callback的三个函数surfaceCreated/surfaceChanged/surfaceDestroyed可以获得Surface创建/变化/销毁的时机
一些常用的函数
setAlpha: 对控件设置透明度变化.
setVisibility: 对控件设置可见性。注意,不可见时surface销毁,可见时surface创建
setZOrderMediaOverlay:将surface view's surface放在同一个window中的另一个surface view上,但仍然在窗口的后面。
setZOrderOnTop:将surface view's surface放在window的最上面
SurfaceView设置背景问题
问题:继承SurfaceView的控件在切换视频以及切换activity时会闪,漏出activity背景
—》surfaceView在渲染好之前会把activity挖空,露出底下的activity内容,视频如果来不及更新,就会看见activity背景
—》SurfaceView在其宿主Activity窗口上所挖的“洞”只不过是在其宿主Activity窗口上设置了一块透明区域。在SurfaceView有内容加载进来之前,那部分一直是透明的
测试方法:
1.将surfaceView的父容器的背景设置为黑色。
this.setBackgroundColor(Color.BLACK);
结果:
没有作用。surfaceView会在当前的activity布局上挖一个洞,这个洞一直到父布局的底层,不管在surfaceView上设置几个父容器,最后surfaceView那块的背景都跟activity背景一样
2.设置surfacview.setZOrderOnTop(true);
结果:
成功解决闪烁问题,这个是把surfaceView绘制的内容放在Z轴的最上层,但是会引发另一个问题:在surfaceview所在视图区域的其他控件全部被他的画布给遮住了。
3.设置setZOrderMediaOverlay(true)
结果:
不会遮挡放在surfaceView上面的控件,但是解决不了闪烁的问题。该方法可以用来将surfaceView放在另一个surfaceView的上面,另一个SurfaceView用来做背景,但是会耗性能
4.在surfaceView第一次生成的时候,用canvas给surfaceView手动绘制一层背景
其他使用surfaceView的问题
问题1:不能在list视图中使用SurfaceView
SurfaceView不支持UI同步缓冲(UI synchronization buffer),这导致当滑动list时视频会丢进度。
问题2:多层嵌套被遮挡:
setZOrderOnTop(boolean onTop) // 在最顶层,会遮挡一切view
setZOrderMediaOverlay(boolean isMediaOverlay)// 如已绘制SurfaceView则在surfaceView上一层绘制。
问题3:不绘制任何东西,SurfaceView显示的是黑色?
每次更新视图时都会先将背景绘制成黑色。所以在移动或者缩放过程,会更新不及时时就会看黑边。
问题4设置背景为透明
surfaceView.setZOrderOnTop(true);
surfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT); // 设置画布 背景透明
surfaceView.getHolder().setFormat(PixelFormat.TRANSPARENT);
参考文档
https://www.jianshu.com/p/e6c99ccd5f12
https://blog.csdn.net/bandaotilan/article/details/75669472
http://www.jeepxie.net/article/975327.html