Android TexureView、SurfaceView 测
背景
最近App开发中遇到了一个场景,需要两到三个SurfaceView做叠层,并涉及到小窗口播放视频的场景,由于SurfaceView的某些限制,无法有个良好的实现,遂调研了一下解决方案,涉及了TexureView,也发现了一些问题,有些问题并没有给自己找到答案,但是整体思路还是比较完整了。
此文解决已问题
- 多层SurfaceView 或者SurfaceView与TexureView混合画面的排布;
- 透明的SurfaceView 模拟AR效果的排布可能遇到问题,只能是多个SurfaceView实现。或多TexureView功能上是无法实现的,TexureView与SurfaceView的混合会遇到问题,并找出原因。
关于重叠的时候出现的问题
使用双Surface 的重叠测试
使用双Surface做重叠操作:
//topsurfaceView.setZOrderOnTop(true);
topsurfaceView.setZOrderMediaOverlay(true); //onAttachedToWindow之前设置
topsurfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT); //可以在onAttach后设置
两个SurfaceView的重叠区域能正常显示,并实现AR场景.
如果Bottom是texureView,VideoView在中间,而SurfaceView 在最上层。如下图所示:
SurfaceView的透明部分一部分能显示VideoView的视频,另外一部分黑色,并没有透明到TexureView,
主要原因从SurfaceView的文档我们知道,surface总是在当前的Window后面绘制出来的,而加入到View Tree里面的只是一占位的View,也就是这么Window的一个洞。由于TexureView在当前的window上,那么SurfaceView的surface在这个Window的后面,所以TextureView会显示黑色,因为后面没有可见的内容了。
注意事项
TextureView如果设置了背景色,将无法绘制
关于这两个类的描述
SurfaceView
android.view.View
↳ android.view.SurfaceView
↳ android.opengl.GLSurfaceView
↳ android.widget.VideoView
Provides a dedicated drawing surface embedded inside of a view hierarchy. You can control the format of this surface and, if you like, its size; the SurfaceView takes care of placing the surface at the correct location on the screen
The surface is Z ordered so that it is behind the window holding its SurfaceView; the SurfaceView punches a hole in its window to allow its surface to be displayed. The view hierarchy will take care of correctly compositing with the Surface any siblings of the SurfaceView that would normally appear on top of it. This can be used to place overlays such as buttons on top of the Surface, though note however that it can have an impact on performance since a full alpha-blended composite will be performed each time the Surface changes.
SurfaceView 提供了一个专门的Surface 嵌入到view Hierarchy中,你能控制这个surface 的格式,大小,位置等.
The Surface是纵深排序(Z-ordered)的,这表明它总在自己所在Window的后面。Surfaceview提供了一个可见区域,只有在这个可见区域内的surface部分内容才可见,可见区域外的部分不可见。surface的排版显示受到视图层级关系的影响,它的兄弟视图结点会在顶端显示。这意味者 surface的内容会被它的兄弟视图遮挡,这一特性可以用来放置遮盖物(overlays)(例如,文本和按钮等控件)。
注意,如果surface上面 有透明控件,那么它的每次变化都会引起框架重新计算它和顶层控件的透明效果,这会影响性能。
TexureView
java.lang.Object
↳ android.view.View
↳ android.view.TextureView
A TextureView can be used to display a content stream. Such a content stream can for instance be a video or an OpenGL scene. The content stream can come from the application's process as well as a remote process.
TextureView can only be used in a hardware accelerated window. When rendered in software, TextureView will draw nothing.
能显示content stream,比如视频或者OpenGL 画面。这个内容流能来源于别的进程,比如Camera.
TextureView 只能用于支持硬件加速的Window,如果用软解渲染,will draw nothing.
关于这两个Class的异同
异
1、在显示实现方面,TextureView没有创建单独的Window,跟SurfaceView是通过对当前的Window挖一个洞透过去显示的;<br />
2、TexureView更普通View一样,更方便与移动、变形、做动画等;<br />
3、TexureView只支持硬件加速,不支持软件解码,注意Activity;<br />
4、TexureView在显示camera 预览是,不允许同时画别的东西,即便是lockCanvas了;<br />
同
1、都能支持堆叠<br />
2、只有在attachedToWindow 后才可用;<br />
相关的一些类的方法
当场景中有多个SurfaceView的时候,上层的SurfaceView可能会被下层的遮挡,这个时候需要使用setZOrderOnTop(true)或者setZOrderMediaOverlay(true)来控制SurfaceView的显示层次。
Android SDK对两个函数的描述:
public void setZOrderOnTop(boolean onTop)
Added in API level 5
Control whether the surface view's surface is placed on top of its window. Normally it is placed behind the window, to allow it to (for the most part) appear to composite with the views in the hierarchy. By setting this, you cause it to be placed above the window. This means that none of the contents of the window this SurfaceView is in will be visible on top of its surface.
Note that this must be set before the surface view's containing window is attached to the window manager.
Calling this overrides any previous call to setZOrderMediaOverlay(boolean).
控制这个surfaceView是否被放在窗口顶层。通常,为了使它与View树整合,它被放在窗口之后。通过这个函数,你可以使SurfaceView被放在窗口顶层。这意味着它所在的窗口的其他内容都不可见。
(注:可以设置surfaceView透明来使其他内容可见)这个函数必须在窗口被添加到窗口管理器之前设置。
调用这个函数会使之前调用的setZOrderMediaOverlay(boolean)无效;
public void setZOrderMediaOverla(boolean isMediaOverlay)
Added in API level 5
Control whether the surface view's surface is placed on top of another regular surface view in the window (but still behind the window itself). This is typically used to place overlays on top of an underlying media surface view.
Note that this must be set before the surface view's containing window is attached to the window manager.
Calling this overrides any previous call to setZOrderOnTop(boolean).
控制这个surfaceView是否被放在另一个普通的surfaceView上面(但是仍然在窗口之后)。这个函数通常被用来将覆盖层至于一个多媒体层上面。
这个函数必须在窗口被添加到窗口管理器之前设置。
调用这个函数会使之前调用的setZOrderOnTop(boolean)无效。
一些知识点
z-ordered
Z-order
is an ordering of overlapping two-dimensional objects, such as windows in a stacking window manager, shapes in a vector graphics editor, or objects in a 3D application.[1] One of the features of a typical GUI is that windows may overlap, so that one window hides part or all of another. When two windows overlap, their Z-order determines which one appears on top of the other.
硬件加速
主要有4个控制级别,下面我举列一下常用的:
//For Application
<root>
<application android:hardwareAccelerated="true" />
</root>
//For Activity
<root>
<application android:hardwareAccelerated="true">
<activity ... />
<activity android:hardwareAccelerated="false" />
</application>
</root>
//For Window
getWindow().setFlags(
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
结语
如果本文中出现了一些问题,希望大家指正,谢谢
[Source Sample Download] (https://github.com/waesteve/CameraAndVideo/tree/master)