1. Window 的概念
- Window 表示一个窗口的概念,类似悬浮窗的交互。Window 是一个抽象类,具体实现是 PhoneWindow
- 创建一个 Window 只需 WindowManager 即可,WindowManager 是外界访问 Window 的入口。WindowManager 和 WindowManagerService 的交互是一个 通过 Binder 来进行 IPC 的过程
- Android 中所有的视图都是通过 Window 来呈现的,不管是 Activity、Dialog 还是 Toast,它们的视图实际上都是附加在 Window 上的,因此 Window 实际是 View 的直接管理者
- View 的事件分发机制中,单击事件由 Window 传递给 DecorView,再由 DecorView 传递给 View
- Activity 的设置视图的方法
setContentView()
方法在底层也是通过 Window 来完成的
2. 通过 WindowManager 添加 Window
1 | // Demo: 将一个 Button 添加到屏幕坐标为 (100, 300) 的位置上 |
3. WindowManager.LayoutParams 中的 flags
Flags 参数表示 Window 的属性,有很多选项,通过这些选项可以控制 Window 的显示特性
Flags 常用的属性值及含义
属性值 含义 FLAG_NOT_FOCUSABLE
表示 Window 不需要获取焦点,也不需要接收各种输入事件,此标记会同时启用 FLAG_NOT_TOUCH_MODAL
,最终事件会直接传递给下层的具有焦点的 WindowFLAG_NOT_TOUCH_MODAL
在此模式下,系统会将当前 Window 区域以外的单击事件传递给底层的 Window,当前 Window 区域以内的单击事件则自己处理。这个标记很重要,一般来说都需要开启此标记,否则其他 Window 将无法收到单击事件 FLAG_SHOW_WHEN_LOCKED
开启此模式可以让 Window 显示在锁屏界面上
4. WindowManager.LayoutParam 中的 type
- Type 参数表示 Window 的类型,Window 有三种类型,分别是应用 Window、子 Window 和系统 Window
- 应用 Window:对应着一个 Activity
- 子 Window:不能单独存在,需要附属在特定的父 Window 之中,比如常见的一些 Dialog 就是一个子 Window
- 系统 Window:需要声明权限才能创建的 Window,比如 Toast 和系统状态栏这些都是系统 Window
5. Window 的分层概念
- Window 是分层的,每个 Window 都有对应的 z-ordered,层级大的 Window 会覆盖在层级小的 Window 上面,这与 HTML 中的 z-index 概念一致
- 在三类 Window 中,应用 Window 的层级范围是 1 ~ 99;子 Window 的层级范围是 1000 ~ 1999;系统 Window 的层级范围是 2000 ~ 2999,这些层级范围对应着
WindowManager.LayoutParams
的type
参数 - 很显然系统 Window 的层级是最大的,而且系统层级有很多值,一般可以选用
TYPE_SYSTEM_OVERLAY
或者TYPE_SYSTEM_ERROR
- 如果采用
TYPE_SYSTEM_ERROR
,只需要为 type 参数指定这个层级即可:mLayoutParams.type = LayoutParams.TYPE_SYSTEM_ERROR;
- 同时声明权限:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
,因为系统类型的 Window 是需要检查权限的
- 如果采用
6. WindowManager 概述
WindowManager 所提供的功能很简单,常用的只有三个方法,即添加 View、更新 View和删除 View。这三个方法定义在 ViewManager 中,而 WindowManager 继承了 ViewManager
ViewManager 定义:
1
2
3
4
5public interface ViewManager {
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view);
}- 可见,WindowManager 操作 Window 的过程更像是在操作 Window 中的 View
Demo:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// 需求:实现一个可以拖动的 Window 效果
// 思路:给 View 设置 onTouchListener,在 onTouch() 方法中根据手指位置来设置 LayoutParams 中 x 和 y 的值即可不断更新 View 的位置
public boolean onTouch(View v, MotionEvent event) {
int rawX = (int) event.getRawX();
int rawY = (int) event.getRawY();
switch(event.getAction()) {
case MotionEvent.ACTION_MOVE:
mLayoutParams.x = rawX;
mLayoutParams.y = rawY;
mWindowManager.updateViewLayout(mFloatingButton, mLayoutParams);
break;
default:
break;
}
return false;
}