Window和WindowManager
Window
是一个抽象类,具体实现是PhoneWindow。Window的具体实现位于WindowManagerService中。所有的视图都是通过Window来呈现的,Window实际是View的直接管理者。
创建Window通过WindowManager
(每个窗口管理器实例都绑定一个特定的Display(即Activity、Dialog))完成,WindowManager是外界访问Window的入口,WindowManager和WindowManagerService的交互是一个IPC过程。
使用WindowManager添加一个Window
mFloatingButton = new Button(this);
mFloatingButton.setText("button");
mLayoutParams = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, 0, 0, PixelFormat.TRANSPARENT);
mLayoutParams.gravity = Gravity.CENTER;
mLayoutParams.x = 100;
mLayoutParams.y = 300;
mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
// 8.0以上需要这样设置type
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mLayoutParams.type = LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
mLayoutParams.type = LayoutParams.TYPE_SYSTEM_ALERT;
}
mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
if (mWindowManager != null) {
mWindowManager.addView(mFloatingButton, mLayoutParams);
}
声明权限
因为 LayoutParams.TYPE_APPLICATION_OVERLAY和LayoutParams.TYPE_SYSTEM_ALERT是系统类型的Window,所以要在AndroidManifest中使用相应的权限
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
此外,还需在代码里手动申请获得手机的相关权限:
if (Build.VERSION.SDK_INT >= 23 && !Settings.canDrawOverlays(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivityForResult(intent, 1);
} else {
addWindow();
}
WindowManager.LayoutParams中的参数
Flags参数
表示Window的属性,可以控制Window的显示特性
1.FLAG_NOT_FOCUSABLE
Window不需要获取焦点,也不需要接收各种输入事件,此标记会同时启用FLAG_NOT_TOUCH_MODAL,最终事件会直接传递给下层的具有焦点的Window
2.FLAG_NOT_TOUCH_MODAL
系统会将当前Window区域以外的单击事件传递给底层的Window,当前Window区域以内的单击事件则自己处理。一般来说都会开启此标记,否则其他Window将无法收到单击事件。
3.FLAG_SHOW_WHEN_LOCKED
可以让Window显示在锁屏的界面上,只适用于最顶层的全屏幕Window。(这个参数在AIP27时过期了,推荐使用 R.attr.showWhenLocked参数或者Activity.setShowWhenLocked(boolean))
Type参数
表示Window的类型
Window的类型
Window是分层的,每个Window都有对应的z-ordered,层级大的会覆盖在层级小的Window上面,层级范围对应着type参数
1.应用Window
对应着一个Activity,层级范围1~99
2.子Window
不能单独存在,需要附属在特定的父Window之中,比如Dialo。层级范围1000~1999
3.系统Window
需要声明权限才能创建,比如Toast和系统状态栏。层级范围2000~2999
// 应用Window的层级范围
public static final int FIRST_APPLICATION_WINDOW = 1;
public static final int LAST_APPLICATION_WINDOW = 99;
// 子Window的层级范围
public static final int FIRST_SUB_WINDOW = 1000;
public static final int LAST_SUB_WINDOW = 1999;
// 系统Window的层级范围
public static final int FIRST_SYSTEM_WINDOW = 2000;
public static final int LAST_SYSTEM_WINDOW = 2999;
WindowManager提供的方法
常用的只有以下三个方法,这三个方法定义在ViewManager中,WindowManager继承了ViewManager
WindowManager操作Window的过程更像是在操作Window中的View
public interface ViewManager {
void addView(View var1, LayoutParams var2);
void updateViewLayout(View var1, LayoutParams var2);
void removeView(View var1);
}