Android WindowManager类

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/chennai1101/article/details/87272276

1. Window和WindowManager

Window有三种类型,层级大的会覆盖在层级小的上面

  • 应用Window,对应Activity,层级范围是 1~99
  • Window,对应DialogPopupWindow,层级范围是 1000~1999
  • 系统Window,对应Toast层级范围是 2000~2999

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);
}

2. 创建悬浮窗

悬浮窗对应系统Window,通过WindowManager.addView(View, ViewGroup.LayoutParams)加入界面

WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
lp.width = ViewGroup.LayoutParams.WRAP_CONTENT;
lp.gravity = Gravity.RIGHT | Gravity.CENTER_VERTICAL; // 窗口位置
lp.format = PixelFormat.TRANSPARENT; // 位图格式
lp.type = WindowManager.LayoutParams.TYPE_TOAST; // 窗口的层级关系
lp.flags= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; // 窗口的模式
wm.addView(view, lp);

WindowManager.LayoutParamstype属性取值

常量 含义
FIRST_APPLICATION_WINDOW 应用程序窗口
TYPE_BASE_APPLICATION 所有程序窗口的“基地”窗口
TYPE_APPLICATION 普通应用功能程序窗口
TYPE_APPLICATION_STARTING 用于应用程序启动时所显示的窗口
LAST_APPLICATION_WINDOW 应用程序窗口结束
FIRST_SUB_WINDOW 子窗口
TYPE_APPLICATION_PANE 面板窗口
TYPE_APPLICATION_MEDIA 媒体窗口
TYPE_APPLICATION_SUB_PANEL 应用程序窗口的子面板
TYPE_APPLICATION_ATTACHED_DIALOG 对话框
TYPE_APPLICATION_MEDIA_OVERLAY 媒体信息
LAST_SUB_WINDOW 子窗口结束
FIRST_SYSTEM_WINDOW 系统窗口
TYPE_STATUS_BAR 状态栏
TYPE_SEARCH_BAR 搜索栏
TYPE_PHONE 电话窗口
TYPE_SYSTEM_ALERT 系统提示
TYPE_KEYGUARD 锁屏窗口
TYPE_TOAST 信息窗口
TYPE_SYSTEM_OVERLAY 系统顶层窗口
TYPE_PRIORITY_PHONE 电话优先,当锁屏时显示
TYPE_SYSTEM_DIALOG 系统对话框(例如音量调节框)
TYPE_KEYGUARD_DIALOG 锁屏时显示的对话框
TYPE_SYSTEM_ERROR 系统内部错误提示,显示于所有内容之上
TYPE_INPUT_METHOD 内部输入法窗口,显示于普通UI之上
TYPE_INPUT_METHOD_DIALOG 内部输入法对话框,显示于当前输入法窗口之上
TYPE_WALLPAPER 墙纸窗口
TYPE_STATUS_BAR_PANEL 状态栏的滑动面板
LAST_SYSTEM_WINDOW 系统窗口结束

WindowManager.LayoutParamsflags属性取值

常量 含义
FLAG_ALLOW_LOCK_WHILE_SCREEN_ON 允许在屏幕开启的时候锁定屏幕
FLAG_DIM_BEHIND window会变暗,使用dimAmount属性来控制变暗的程度
FLAG_NOT_FOCUSABLE window永远不会获取焦点
FLAG_NOT_TOUCHABLE window永远无法获取点击事件
FLAG_NOT_TOUCH_MODAL 允许window之外点击事件传递给其他在其之后的window
FLAG_TOUCHABLE_WHEN_WAKING device休眠的时候,当触摸屏被点击,window会收到首次点击事件
FLAG_KEEP_SCREEN_ON 当这个window对用户是可见状态,保持设备屏幕不关闭且不变暗
FLAG_LAYOUT_IN_SCREEN 将window放置在整个屏幕之内,无视其他的装饰
FLAG_LAYOUT_NO_LIMITS 允许window扩展至屏幕之外
FLAG_FULLSCREEN 当这个window显示的时候,隐藏所有的装饰物
FLAG_FORCE_NOT_FULLSCREEN 覆盖FLAG_FULLSCREEN效果,并强制显示屏幕上的一些装饰
FLAG_SECURE 把这个window中的内容看作需要保护的内容,防止被截屏
FLAG_SCALED 一种特殊模式,布局参数用于指示显示比例
FLAG_IGNORE_CHEEK_PRESSES 会过滤不需要的点击事件
FLAG_LAYOUT_INSET_DECOR 这个flag只能配合 FLAG_LAYOUT_IN_SCREEN 一起使用
FLAG_ALT_FOCUSABLE_IM 反转FLAG_NOT_FOCUSABLE选项
FLAG_WATCH_OUTSIDE_TOUCH 一个点击事件如果发生在你的window之外的范围,你就会接收到一个特殊的MotionEvent,MotionEvent.ACTION_OUTSIDE
FLAG_SHOW_WHEN_LOCKED 使得window可以在锁屏状态下显示
FLAG_SHOW_WALLPAPER 如果你的window有透明的区域,墙纸会显示在那
FLAG_TURN_SCREEN_ON 当window被添加或者显示,系统会点亮屏幕
FLAG_DISMISS_KEYGUARD 当使用的是无密码的锁屏界面,显示此window会使锁屏界面被自动解锁
FLAG_SPLIT_TOUCH window会接收来自window边界之外发送给其他window的点击事件
FLAG_HARDWARE_ACCELERATED window是否启动硬件加速,请求硬件加速但不能保证硬件加速生效
FLAG_LOCAL_FOCUS_MODE 在这种模式下,window不会通过windowmanager获取到event
FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS window负责绘制状态栏的背景

创建悬浮窗需要系统权限

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

3. 悬浮窗禁用

在Android6.0以后,悬浮窗权限默认是禁用的,需要用户确定打开,在返回时确认权限。

public void requestPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
            && !Settings.canDrawOverlays(this)) {
        Toast.makeText(this, "请授权!", Toast.LENGTH_SHORT).show();
        Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                Uri.parse("package:" + getPackageName()));
        startActivityForResult(intent, REQUEST_OVERLAY_PERMISSION);
    } else {
        showSuspensionWindow(mSuspensionView);
    }
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == REQUEST_OVERLAY_PERMISSION) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Settings.canDrawOverlays(this)) {
            showSuspensionWindow(mSuspensionView);
        }
    }
}

参考资料: https://blog.csdn.net/yhaolpz/article/details/68936932
参考资料: https://blog.csdn.net/core_ice/article/details/52464125

猜你喜欢

转载自blog.csdn.net/chennai1101/article/details/87272276