Android进阶——自定义View之WindowManager概述及利用WindowManager实现悬浮所有界面之上的悬浮窗Floating View(一)

引言

悬浮窗相信大家都不陌生,比如各种手机管理软件上的加速球,视频应用的小窗,可以以很少的空间换来较高的用户体验。记得我最初接触到悬浮窗就是流氓卫士的加速球,反编译后发现里面有个FloatingView的东西,初学的时候还以为是系统自带的控件,后来才知道本质上就是利用WindowManager.addView实现的,一定程度上来说实现并不难,复杂之处在于适配各种ROM 获取悬浮窗权限。

一、WindowManager概述

WindowManager是Android系统中一个重要的服务,WindowManager Service 是全局且唯一的。从它的源码注释——The interface that apps use to talk to the window manager我们知道它是app与window 交互的接口,它将用户的操作,翻译成为指令,发送给呈现在界面上的各个Window。而在Activity会将顶级的控件注册到 Window Manager 中,所以当用户真实触碰屏幕或键盘的时候,Window Manager就会通知到;还有当控件有一些请求产生时也会经由ViewParent送回到Window Manager中,从而完成整个通信流程。总而言之,整个Android的窗口机制是基于一个叫做 WindowManager的接口,通过这个接口可以通过addView方法添加view到屏幕,也可以通过removeView方法从屏幕删除view。因为它面向的对象一端是屏幕,另一端就是View,最终通过WindowManager的 创建View,并根据WindowManager.LayoutParams属性不同,效果也就不同了。比如创建系统顶级窗口,实现悬浮窗口效果。

二、WindowManager.LayoutParams 概述

WindowManager.LayoutParams继承自ViewGroup.LayoutParams 并实现Parcelable接口,是 WindowManager 接口的嵌套类,也是WindowManager中重要的一个嵌套类,用于描述View的布局、大小信息等。

WindowManager.LayoutParams重要的属性 说明
public int x 如果忽略gravity属性,那么它表示窗口的绝对X位置。什么是gravity属性呢?简单地说,就是窗口如何停靠。当设置了 Gravity.LEFT 或 Gravity.RIGHT 之后,x值就表示到特定边的距离。
public int y 如果忽略gravity属性,那么它表示窗口的绝对Y位置。当设置了 Gravity.TOP 或 Gravity.BOTTOM 之后,y值就表示到特定边的距离。
public float horizontalWeight 在水平(横)向上,为关联的view预留了多少扩展空间(像素)。如果是0,那么此view不能被拉伸。其他情况下,扩展空间(像素)将被widget所均分。
public float verticalWeight 在垂直(纵)向上,为关联的view预留了多少扩展空间(像素)。如果是0,那么此view不能被拉伸。其他情况下,扩展空间(像素)将被widget所均分。
public int type 窗口类型,详见下文
public int memoryType 指出窗口所使用的内存缓冲类型。取值为: public static final int MEMORY_TYPE_NORMAL = 0表示窗口缓冲位于主内存(默认); MEMORY_TYPE_HARDWARE = 1表示窗口缓冲位于可以被DMA访问,或者硬件加速的内存区域;MEMORY_TYPE_GPU = 2;表示 窗口缓冲位于可被图形加速器访问的区域; MEMORY_TYPE_PUSH_BUFFERS = 3表示 窗口缓冲不拥有自己的缓冲区,不能被锁定。缓冲区由本地方法提供。
public int flags 行为选项配置,参见下文
public in softInputMode 软输入法配置,参见下文
public int gravity 就是窗口如何停靠的位置
public float horizontalMargin 水平边距,容器与widget之间的距离,占容器宽度的百分率。
public float verticalMargin 纵向边距。
public int format 期望的位图格式。默认为不透明。参考android.graphics.PixelFormat。
public int windowAnimations 窗口所使用的动画设置。它必须是一个系统资源而不是应用程序资源,因为窗口管理器不能访问应用程序。
public float alpha = 1.0f 整个窗口的半透明值,1.0表示不透明,0.0表示全透明。
public float dimAmount = 1.0f 当FLAG_DIM_BEHIND设置后生效。该变量指示后面的窗口变暗的程度。1.0表示完全不透明,0.0表示没有变暗。
public float screenBrightness = -1.0f 用来覆盖用户设置的屏幕亮度。表示应用用户设置的屏幕亮度。从0到1调整亮度从暗到最亮发生变化。
public IBinder token = null 窗口的标示符。( Identifier for this window. This will usually be filled in for you. )
public String packageName = null 此窗口所在的包名。
public int screenOrientation =ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED 屏幕方向,参见android.content.pm.ActivityInfo#screenOrientation。

1、type简介

type有三大主要类型:

  • Applicationwindows——取值在 FIRST_APPLICATION_WINDOW 和 LAST_APPLICATION_WINDOW 之间。是通常的、顶层的应用程序窗口且必须将 token 设置成 activity 的 token 。

  • Sub_windows——取值在 FIRST_SUB_WINDOW 和 LAST_SUB_WINDOW 之间。与顶层窗口相关联,token 必须设置为它所附着的宿主窗口的 token。

  • Systemwindows——取值在 FIRST_SYSTEM_WINDOW 和 LAST_SYSTEM_WINDOW 之间。用于特定的系统功能。它不能用于应用程序,使用时需要特殊权限。

type 取值范围如下表:

type常量值 说明
public static final int FIRST_APPLICATION_WINDOW = 1 应用程序窗口。
public static final int TYPE_BASE_APPLICATION =1 所有程序窗口的“base”窗口,其他应用程序窗口都显示在它上面。
public static final int TYPE_APPLICATION = 2 普通应用功能程序窗口。token必须设置为Activity的token,以指出该窗口属谁。
public static final int TYPE_APPLICATION_STARTING = 3; 用于应用程序启动时所显示的窗口。应用本身不要使用这种类型,它用于让系统显示些信息,直到应用程序可以开启自己的窗口。
public static final int LAST_APPLICATION_WINDOW = 99 应用程序窗口结束。
public static final int FIRST_SUB_WINDOW = 1000 子窗口,子窗口的Z序和坐标空间都依赖于他们的宿主窗口。
public static final int TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW 面板窗口,显示于宿主窗口上层。
public static final int TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW+1 媒体窗口,例如视频。显示于宿主窗口下层。
public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW +2 应用程序窗口的子面板。显示于所有面板窗口的上层。(GUI的一般规律,越“子”越靠上)
public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW +3 对话框。类似于面板窗口,绘制类似于顶层窗口,而不是宿主的子窗口。
public static final int TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW +4; 媒体信息。显示在媒体层和程序窗口之间,需要实现透明(半透明)效果。(例如显示字幕)
public static final int LAST_SUB_WINDOW = 1999; 子窗口结束。( End of types of sub-windows )
public static final int FIRST_SYSTEM_WINDOW = 2000 系统窗口。非应用程序创建。
public static final int TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW 状态栏。只能有一个状态栏;它位于屏幕顶端,其他窗口都位于它下方。
public static final int TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1 搜索栏。只能有一个搜索栏;它位于屏幕上方。
public static final int TYPE_PHONE = FIRST_SYSTEM_WINDOW+2 电话窗口。它用于电话交互(特别是呼入)。它置于所有应用程序之上,状态栏之下。
public static final int TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW +3 系统提示。它总是出现在应用程序窗口之上。
public static final int TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW +4 锁屏窗口。
public static final int TYPE_TOAST = FIRST_SYSTEM_WINDOW +5 信息窗口。用于显示toast。
public static final int TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW +6 系统顶层窗口。显示在其他一切内容之上。此窗口不能获得输入焦点,否则影响锁屏。
public static final int TYPE_PRIORITY_PHONE = FIRST_SYSTEM_WINDOW +7 电话优先,当锁屏时显示。此窗口不能获得输入焦点,否则影响锁屏。
public static final int TYPE_SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW +8 系统对话框。(例如音量调节框)。
public static final int TYPE_KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW +9 锁屏时显示的对话框。
public static final int TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW +10 系统内部错误提示,显示于所有内容之上。
public static final int TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW +11 内部输入法窗口,显示于普通UI之上。应用程序可重新布局以免被此窗口覆盖。
public static final int TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW +12 内部输入法对话框,显示于当前输入法窗口之上。
public static final int TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW +13 墙纸窗口
public static final int TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW +14 状态栏的滑动面板。
public static final int LAST_SYSTEM_WINDOW = 2999 系统窗口结束

2、flags

flags常量值 说明
static final int FLAG_DIM_BEHIND = 0x00000002 窗口之后的内容变暗
static final int FLAG_BLUR_BEHIND = 0x00000004 窗口之后的内容变模糊
static final int FLAG_NOT_FOCUSABLE 不许获得焦点
static final int FLAG_NOT_TOUCHABLE = 0x00000010 不接受触摸屏事件
static final int FLAG_NOT_TOUCH_MODAL = 0x00000020 当窗口可以获得焦点(没有设置 FLAG_NOT_FOCUSALBE 选项)时,仍然将窗口范围之外的点设备事件(鼠标、触摸屏)发送给后面的窗口处理。否则它将独占所有的点设备事件,而不管它们是不是发生在窗口范围内。
static final int FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040 设置了这个标志,当设备休眠时,点击触摸屏,设备将收到这个第一触摸事件。通常第一触摸事件被系统所消耗,用户不会看到他们点击屏幕有什么反应。
static final int FLAG_KEEP_SCREEN_ON = 0x00000080 窗口为用户可见时,保持设备常开,并保持亮度不变
static final int FLAG_LAYOUT_IN_SCREEN =0x00000100 窗口占满整个屏幕,忽略周围的装饰边框(例如状态栏)。此窗口需考虑到装饰边框的内容
static final int FLAG_LAYOUT_NO_LIMITS =0x00000200 允许窗口扩展到屏幕之外
static final int FLAG_FULLSCREEN = 0x00000400 窗口显示时,隐藏所有的屏幕装饰(例如状态条)。使窗口占用整个显示区域
static final int FLAG_FORCE_NOT_FULLSCREEN =0x00000800 将覆盖FLAG_FULLSCREEN选项,并强制屏幕装饰(如状态条)弹出
static final int FLAG_DITHER = 0x00001000 抖动。指对半透明的显示方法。又称“点透”。图形处理较差的设备往往用“点透”替代Alpha混合
static final int FLAG_SECURE = 0x00002000 不允许屏幕截图
static final int FLAG_SCALED = 0x00004000 一种特殊模式,布局参数用于指示显示比例。
static final int FLAG_IGNORE_CHEEK_PRESSES = 0x00008000 当屏幕有可能贴着脸时,这一选项可防止面颊对屏幕造成误操作。
static final int FLAG_LAYOUT_INSET_DECOR = 0x00010000 当请求布局时,你的窗口可能出现在状态栏的上面或下面,从而造成遮挡。当设置这一选项后,窗口管理器将确保窗口内容不会被装饰条(状态栏)盖住。
static final int FLAG_ALT_FOCUSABLE_IM = 0x00020000 反转FLAG_NOT_FOCUSABLE选项。如果同时设置了FLAG_NOT_FOCUSABLE选项和本选项,窗口将能够与输入法交互,允许输入法窗口覆盖;如果FLAG_NOT_FOCUSABLE没有设置而设置了本选项,窗口不能与输入法交互,可以覆盖输入法窗口。
static final int FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000 如果你设置了FLAG_NOT_TOUCH_MODAL,那么当触屏事件发生在窗口之外事,可以通过设置此标志接收到一个 MotionEvent.ACTION_OUTSIDE事件。注意,你不会收到完整的down/move/up事件,只有第一次down事件时可以收到 ACTION_OUTSIDE。
static final int FLAG_SHOW_WHEN_LOCKED = 0x00080000 当屏幕锁定时,窗口可以被看到。这使得应用程序窗口优先于锁屏界面。可配合FLAG_KEEP_SCREEN_ON选项点亮屏幕并直接显示在锁屏界面之前。可使用FLAG_DISMISS_KEYGUARD选项直接解除非加锁的锁屏状态。此选项只用于最顶层的全屏幕窗口。
static final int FLAG_SHOW_WALLPAPER = 0x00100000 请求系统墙纸显示在你的窗口后面。窗口必须是半透明的。
static final int FLAG_TURN_SCREEN_ON = 0x00200000 窗口一旦显示出来,系统将点亮屏幕,正如用户唤醒设备那样。
static final int FLAG_DISMISS_KEYGUARD = 0x00400000 解除锁屏。只有锁屏界面不是加密的才能解锁。如果锁屏界面是加密的,那么用户解锁之后才能看到此窗口,除非设置了FLAG_SHOW_WHEN_LOCKED选项。
static final int FLAG_KEEP_SURFACE_WHILE_ANIMATING =0x10000000 锁屏界面淡出时,继续运行它的动画。
static final int FLAG_COMPATIBLE_WINDOW = 0x20000000 以原始尺寸显示窗口。用于在兼容模式下运行程序。
static final int FLAG_SYSTEM_ERROR = 0x40000000 用于系统对话框。设置此选项的窗口将无条件获得焦点。

3、softInputMode

softInputMode 取值 说明
static final int SOFT_INPUT_MASK_STATE=0x0f 软输入区域是否可见。
static final int SOFT_INPUT_STATE_UNSPECIFIED=0 未指定状态。
static final int SOFT_INPUT_STATE_UNCHANGED=1 不要修改软输入法区域的状态。
static final int SOFT_INPUT_STATE_HIDDEN=2 隐藏输入法区域(当用户进入窗口时)。
static final int SOFT_INPUT_STATE_ALWAYS_HIDDEN=3 当窗口获得焦点时,隐藏输入法区域。
static final int SOFT_INPUT_STATE_VISIBLE=4 显示输入法区域(当用户进入窗口时)。
static final int SOFT_INPUT_STATE_ALWAYS_VISIBLE=5 当窗口获得焦点时,显示输入法区域。
static final int SOFT_INPUT_MASK_ADJUST=0xf0 窗口应当主动调整,以适应软输入窗口。
static final int SOFT_INPUT_ADJUST_UNSPECIFIED=0x00 未指定状态,系统将根据窗口内容尝试选择一个输入法样式。
static final int SOFT_INPUT_ADJUST_RESIZE=0x10 当输入法显示时,允许窗口重新计算尺寸,使内容不被输入法所覆盖。不可与SOFT_INPUT_ADJUSP_PAN混合使用,如果两个都没有设置,系统将根据窗口内容自动设置一个选项。
static final int SOFT_INPUT_ADJUST_PAN=0x20 输入法显示时平移窗口。它不需要处理尺寸变化,框架能够移动窗口以确保输入焦点可见。不可与SOFT_INPUT_ADJUST_RESIZE混合使用;如果两个都没设置,系统将根据窗口内容自动设置一个选项。
static final int SOFT_INPUT_IS_FORWARD_NAVIGATION=0x100 当用户转至此窗口时,由系统自动设置,所以你不要设置它。当窗口显示之后该标志自动清除。

三、借助WindowManager 实现所有界面的悬浮窗

Android进阶——自定义View之WindowManager概述及利用WindowManager实现悬浮所有界面之上的悬浮窗Floating View(一)_第1张图片
详见下篇。

你可能感兴趣的:(Android,进阶,Android自定义View)