0%

理解 Window 和 WindowManager(一):Window 和 WindowManager

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
2
3
4
5
6
7
8
9
// Demo: 将一个 Button 添加到屏幕坐标为 (100, 300) 的位置上
mFloatingButton = new Button(this);
mFloatingButton.setText("button");
mLayoutParam = new WindowManager.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 0, 0, PixelFormat.TRANSPARENT);
mLayoutParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL | LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_SHOW_WHEN_LOCKED
mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
mLayoutParams.x = 100;
mLayoutParams.y = 300;
mWindowManager.addView(mFloatingButton, mLayoutParams);

3. WindowManager.LayoutParams 中的 flags

  • Flags 参数表示 Window 的属性,有很多选项,通过这些选项可以控制 Window 的显示特性

  • Flags 常用的属性值及含义

    属性值 含义
    FLAG_NOT_FOCUSABLE 表示 Window 不需要获取焦点,也不需要接收各种输入事件,此标记会同时启用 FLAG_NOT_TOUCH_MODAL,最终事件会直接传递给下层的具有焦点的 Window
    FLAG_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.LayoutParamstype 参数
  • 很显然系统 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
    5
    public 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;
    }
-------------------- 本文结束感谢您的阅读 --------------------