Window和WindowManager(一)

Window是一个抽象类,表示一个窗口,他的具体实现类是PhoneWindow。创建一个Window是很简单的事,只需要通过WindowManager即可完成。WindowManager是外界访问Window的入口,Window的具体实现位于WindowManagerService中,WindowManager与WindowManagerService的交互是一个IPC过程。Android中所有的试图都是通过Window来呈现的,不管Activity、Dialog还是Toast,他们实际上都是附加在Window上的,因此,Window是View的直接管理者。

Window分类

Window 有三种类型,分别是应用 Window子 Window系统 Window。应用类 Window 对应一个 Acitivity,子 Window 不能单独存在,需要依附在特定的父 Window 中,比如常见的一些 Dialog 就是一个子 Window。系统 Window是需要声明权限才能创建的 Window,比如 Toast 和系统状态栏都是系统 Window。

Window 是分层的,每个 Window 都有对应的 z-ordered,层级大的会覆盖在层级小的 Window 上面,这和 HTML 中的 z-index 概念是完全一致的。在三种 Window 中,应用 Window 层级范围是 1~99,子 Window 层级范围是 1000~1999,系统 Window 层级范围是 2000~2999,我们可以用一个表格来直观的表示:

Window 层级
应用 Window 1~99
子 Window 1000~1999
系统 Window 2000~2999

这些层级范围对应着 WindowManager.LayoutParams 的 type 参数,如果想要 Window 位于所有 Window 的最顶层,那么采用较大的层级即可,很显然系统 Window 的层级是最大的,当我们采用系统层级时,需要声明权限。

WindowManager使用

我们对 Window 的操作是通过 WindowManager 来完成的,WindowManager 是一个接口,它继承自只有三个方法的 ViewManager 接口:

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 对外提供的主要功能,即添加 View、更新 View 和删除 View。接下来来看一个通过 WindowManager 添加 Window 的例子,代码如下:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Button floatingButton = new Button(this);
        floatingButton.setText("button");
        WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                0, 0,
                PixelFormat.TRANSPARENT
        );
        // flag 设置 Window 属性
        layoutParams.flags= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
        // type 设置 Window 类别(层级)
        layoutParams.type = WindowManager.LayoutParams.TYPE_TOAST;
        layoutParams.gravity = Gravity.CENTER;
        WindowManager windowManager = getWindowManager();
        windowManager.addView(floatingButton, layoutParams);

    }
}

代码中并没有调用 Activity 的 setContentView 方法,而是直接通过 WindowManager 添加 Window,其中设置为系统 Window,所以应该添加权限:

    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

Flags表示Window的属性,它有很多选项,通过这些属性可以控制Window的显示属性。

FLAG_NOT_FOCUSABLE

表示window不会获取焦点,也不会接受任何输入事件,此属性会同时启用FLAG_NOT_TOUCH_MODAL,最终事件会直接传递给下层具有焦点的Window。

FLAG_NOT_TOUCH_MODAL

表示在当前Window以外的点击事件会传递给底层Window,以内的则由当前window处理。这个标记很重要,一般来说都需要开启,否则其他Window将无法收到点击事件。

FLAG_SHOW_WHEN_LOCKED

开启此模式可以让window显示在锁屏界面上。比如QQ的消息

注意:如果设置

WindowManager.LayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT

在level 19以上的版本就会报下面的error:

android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@40ec8528 -- permission denied for this window type

原因见:https://stackoverflow.com/questions/32224452/android-unable-to-add-window-permission-denied-for-this-window-type

所以,一般会用LayoutParams.TYPE_TOAST or TYPE_APPLICATION_PANEL

效果如下:
Window和WindowManager(一)_第1张图片

你可能感兴趣的:(Android-随笔,android,window,窗口)