setZOrderOnTop(true) 以修改 mSubLayer

简介: q

LayoutInflater 布局填充阶段,按既有的布局填充流程,将 SurfaceView 构造并加入到视图树的某个结点;接下来,根布局会通过深度遍历依次执行 onAttachedToWindow() 处理视图挂载窗口的事件:

// /frameworks/base/core/java/android/view/SurfaceView.java
@Override
protected void onAttachedToWindow() {

// ...
mParent.requestTransparentRegion(SurfaceView.this);   // 1.
ViewTreeObserver observer = getViewTreeObserver();
observer.addOnPreDrawListener(mDrawListener);         // 2.

}

@UnsupportedAppUsage
private final ViewTreeObserver.OnPreDrawListener mDrawListener = new ViewTreeObserver.OnPreDrawListener() {

@Override
public boolean onPreDraw() {
    updateSurface();                                 // 3.
    return true;
}

};

protected void updateSurface() {
// ...
mSurfaceSession = new SurfaceSession();
mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession); // 4
//...
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
步骤 1 中,SurfaceView 会向父视图依次向上请求创造一份透明区域,根视图统计到最终的信息后,通过 Binder 通知 WindowManagerService 将对应区域设置为透明。

步骤 2、3、4 是在同一个方法的调用栈中,由此可见,SurfaceView 向系统请求透明区域后,会立即创建一个与绘图表面的连接 SurfaceSession ,并创建一个对应的控制器 SurfaceControl,便于对这个独立的绘图表面进行直接通信。

由此可见,Android 自有的视图树体系中,SurfaceView 作为一个普通的 View 被挂载上去之后,通过 Binder 通信,WindowManagerService 将其所在区域设置为透明(挖洞);并建立了与独立绘图表面的连接,后续便可与其直接通信。

  1. 子图层类型

在阐述绘制流程之前,读者需简单了解 子图层类型 的概念。

上文说到,SurfaceView 的绝大多数使用场景中,其 z 轴的位置通常是在页面的 最下方 。但在实际开发中,随着业务场景复杂度的上升,仍然有部分场景是无法被满足的,比如:在页面的最上方播放一条全屏的视频广告。

因此,SurfaceView 的设计中引入了一个 子图层类型 的概念,用于定义这个独立的 Surface 相比较当前页面窗口 (即Activity) 的位置:

// /frameworks/base/core/java/android/view/SurfaceView.java
public class SurfaceView extends View {

// SurfaceView 的子图层类型
int mSubLayer = APPLICATION_MEDIA_SUBLAYER;

// SurfaceView 是否展示在当前窗口的最上方
// 该方法在挖洞和绘制流程中都有使用,最终影响到用户的视觉效果
private boolean isAboveParent() {

return mSubLayer >= 0;

}
}

// /frameworks/base/core/java/android/view/WindowManagerPolicyConstants.java
public interface WindowManagerPolicyConstants {
// ...
int APPLICATION_MEDIA_SUBLAYER = -2;
int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
int APPLICATION_PANEL_SUBLAYER = 1;
int APPLICATION_SUB_PANEL_SUBLAYER = 2;
int APPLICATION_ABOVE_SUB_PANEL_SUBLAYER = 3;
// ...
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
如代码所示,mSubLayer 默认值为 -2,这表示 SurfaceView 默认总是在 Activity 的下方,想要让 SurfaceView 展示在 Activity 上方,可以调用 setZOrderOnTop(true) 以修改 mSubLayer 的值:
————————————————

相关文章
|
7月前
|
XML Java 数据格式
面试题:怎样把所有的组件的lazy-init值都设置为默认true?
面试题:怎样把所有的组件的lazy-init值都设置为默认true?
64 0
|
Python
a is b 为 True,a == b 一定为 True 吗?
a is b 为 True,a == b 一定为 True 吗?
124 0
|
应用服务中间件
reloadable=“false“ 的作用
reloadable=“false“ 的作用
142 0
[]==![](true)、{}==!{}(false)
[]==![](true)、{}==!{}(false)
122 0
|
Java 程序员
for(;;)和while(true)的区别
for(;;)和while(true)的区别
144 0
for(;;)和while(true)的区别
|
Java 编译器 C语言
for(;;)和while(true)的区别
for(;;)和while(true)的区别
148 0
for(;;)和while(true)的区别
|
编译器
for( ; ; )和while(true)的区别
喜欢看源码的同学可能都会发现,很多组件的作者在做死循环时,都喜欢用for( ; ; ),while(true)或者while(1)也能实现死循环,为啥大佬们都用for( ; ; )呢
4396 0
for( ; ; )和while(true)的区别