很多 iPhone 用户都喜欢打开一项设置,那就是 AssistiveTouch ,我们俗称小白点,它位于整个屏幕之上,就像是漂浮在所有的 App 之上。Android 手机上也有很多应用有这样的东西,比如 360 或者其他主要是手机管家之类的软件。

在之前的公司项目中也有用到这样的悬浮窗,虽然权限有些敏感,但是还算是比较常用,所以在这里记录一下它的基本使用。

1、基本使用

它的基本使用步骤是不会变的,只是有时候我们可能根据不同需求会改变它样式的参数,写一个 demo ,首先记得在 manifests.xml 清单文件中添加权限(但是这个权限好像并不一定所有的手机都会在程序运行的时候询问是否允许添加悬浮窗,这是需要注意的地方):

    <!-- 允许程序添加悬浮窗 --><uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

然后在 Activity 中添加一个悬浮窗:

public class MainActivity extends AppCompatActivity {private WindowManager mWindowManager;private View floatWindowView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//Activity中的方法,得到窗口管理器mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);//设置悬浮窗布局属性WindowManager.LayoutParams mWindowLayoutParams = new WindowManager.LayoutParams();//设置类型,具体有哪些值可取在后面附上mWindowLayoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;//设置行为选项,具体有哪些值可取在后面附上mWindowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;//设置悬浮窗的显示位置mWindowLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
//        //设置悬浮窗的横竖屏,会影响屏幕方向,只要悬浮窗不消失,屏幕方向就会一直保持,可以强制屏幕横屏或竖屏
//        mWindowLayoutParams.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;//设置 x 轴的偏移量mWindowLayoutParams.x = 0;//设置 y 轴的偏移量mWindowLayoutParams.y = 0;//如果悬浮窗图片为透明图片,需要设置该参数为 PixelFormat.RGBA_8888mWindowLayoutParams.format = PixelFormat.RGBA_8888;//设置悬浮窗的宽度mWindowLayoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;//设置悬浮窗的高度mWindowLayoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;//设置悬浮窗的布局floatWindowView = LayoutInflater.from(this).inflate(R.layout.float_window, null);//加载显示悬浮窗mWindowManager.addView(floatWindowView, mWindowLayoutParams);}@Overrideprotected void onDestroy() {super.onStop();mWindowManager.removeView(floatWindowView);}}

注释中提到悬浮窗只要不消失,屏幕方向就会一直保持,如果设置悬浮窗横屏,将程序退到后台时,则手机桌面也会横屏,看起来就会很不舒服,所以如果不是特定需求(比如我之前做的项目需要在某些时刻让手机桌面也横屏),我们可以在 onStart() 的时候添加悬浮窗,然后在 onStop() 方法的时候调用 WindowManager 的 removeView() 方法让其消失,就不会影响屏幕方向了。需要注意的时候不能重复添加同一个悬浮窗,否则会报  java.lang.IllegalStateException: View android.widget.LinearLayout{3284dae1 V.E..... ......I. 0,0-0,0} has already been added to the window manager的异常,所以在添加悬浮窗之前最好先判断一下该悬浮窗是否已添加,具体怎么做我们可以自己设置一个 boolean 类型的标识量默认为 false ,在 addView() 之后设为 true ,removeView() 之后设为 false ,添加之前则先进行判断,true 则不添加,为 false 的时候才添加。

2、type 和 flags 可取值

2.1 type 可取值

应用程序窗口。
public static final int FIRST_APPLICATION_WINDOW = 1;

所有程序窗口的“基地”窗口,其他应用程序窗口都显示在它上面。     
public static final int TYPE_BASE_APPLICATION =1;
    
普通应用功能程序窗口。token必须设置为Activity的token,以指出该窗口属谁。
public static final int TYPE_APPLICATION = 2;

用于应用程序启动时所显示的窗口。应用本身不要使用这种类型。
它用于让系统显示些信息,直到应用程序可以开启自己的窗口。   
public static final int TYPE_APPLICATION_STARTING = 3; 
     
应用程序窗口结束。
public static final int LAST_APPLICATION_WINDOW = 99;

子窗口。子窗口的Z序和坐标空间都依赖于他们的宿主窗口。
public static final int FIRST_SUB_WINDOW = 1000;

面板窗口,显示于宿主窗口上层。
public static final int TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW;

媒体窗口,例如视频。显示于宿主窗口下层。
public static final int TYPE_APPLICATION_MEDIA  = FIRST_SUB_WINDOW+1;

应用程序窗口的子面板。显示于所有面板窗口的上层。(GUI的一般规律,越“子”越靠上)
public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW +2;

对话框。类似于面板窗口,绘制类似于顶层窗口,而不是宿主的子窗口。
public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW +3;

媒体信息。显示在媒体层和程序窗口之间,需要实现透明(半透明)效果。(例如显示字幕)
public static final int TYPE_APPLICATION_MEDIA_OVERLAY  = FIRST_SUB_WINDOW +4;

子窗口结束。( End of types of sub-windows )
public static final int LAST_SUB_WINDOW = 1999;

系统窗口。非应用程序创建。
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;

信息窗口。用于显示toast。
public static final int TYPE_TOAST = FIRST_SYSTEM_WINDOW +5;

系统顶层窗口。显示在其他一切内容之上。此窗口不能获得输入焦点,否则影响锁屏。
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;

内部输入法窗口,显示于普通UI之上。应用程序可重新布局以免被此窗口覆盖。
public static final int TYPE_INPUT_METHOD =  FIRST_SYSTEM_WINDOW +11;

这个值我也不是每个都试过,所以具体效果会有什么不同不能妄言,除了常用的 TYPE_PHONE 外我还使用过一个 TYPE_TOAST,因为刚才有说这个权限不是所有的手机都会在程序第一次运行的时候去询问是否允许该权限,所以用户不知道有这个权限的存在,不允许该权限的话,有些效果又出不来,当设置为 TYPE_TOAST 时,部分手机可以在不允许该权限的情况下也能添加悬浮窗,但仅限于部分手机。

2.2 flags 可取值

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

3、小结

最近待业中,找工作的同时在写一个小时候玩过的游戏——魔塔,准备用 Android 写一个,方便无聊的时候在手机上玩玩,是准备完全移植从前网页上的那个小游戏,所以最近也没有写博客。但需要用到悬浮窗的时候才发现虽然之前写过,但是也不能直接敲出来代码,还得复制,说明用过的东西并不一定会啊,好记性不如写博客,这次决定记录下来,下次再用的时候就不用到处去百度了,无聊的时候看看,争取默熟于心,今后不复制也能自己敲出来。

Android 悬浮窗基本使用相关推荐

  1. android悬浮窗语音识别demo

    带有android悬浮窗的语音识别语义理解demo 如发现代码排版问题,请访问CSDN博客 Android桌面悬浮窗实现比较简单,本篇以一个语音识别,语义理解的demo来演示如何实现android悬浮 ...

  2. Android 悬浮窗功能的实现

    前言 我们大多数在两种情况下可以看到悬浮窗,一个是视频通话时的悬浮窗,另一个是360卫士的悬浮球,实现此功能的方式比较多,这里以视频通话悬浮窗中的需求为例.编码实现使用Kotlin.Java版本留言邮 ...

  3. Android悬浮窗的简单实现

    1. 前言 现在很多应用都有小悬浮窗的功能,比如看直播的时候,通过Home键返回桌面,直播的小窗口仍可以在屏幕上显示.下面将介绍下悬浮窗的的一种简单实现方式. 2.原理 Window我们应该很熟悉,它 ...

  4. Android悬浮窗的实现

    Android悬浮窗的实现 *本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 本文也发布于本人的知乎文章:https://zhuanlan.zhihu.com/p/39421112 ...

  5. Android悬浮窗原理解析(Window)[源码]

    悬浮窗,在大多数应用中还是很少见的,目前我们接触到的悬浮窗,差不多都是一些系统级的应用软件,例如:360安全卫士,腾讯手机管家等:在某些服务行业如金融,餐饮等,也会在应用中添加悬浮窗,例如:美团的偷红 ...

  6. 安卓java浮层不响应点击事件,Android悬浮窗屏蔽悬浮窗外部所有的点击事件的实例代码...

    Android可以在所有应用上方添加View,就是给WindowManager添加一个View,在创建的View的时候可以给这个View设置LayoutParams(android.view.Wind ...

  7. Android展开悬浮窗功能,Android 悬浮窗 (附圆形菜单悬浮窗)

    序言 Android悬浮窗的实现,主要有四个步骤: 1. 声明及申请权限 2. 构建悬浮窗需要的控件 3. 将控件添加到WindowManager 4. 必要时更新WindowManager的布局 一 ...

  8. android动态获取悬浮窗,Android 悬浮窗实现

    Android悬浮窗实现中需要注意的两点是 1.Android 6.0之后的悬浮窗动态申请 2.Window 的type属性在Android8.0前后的适配 public abstract class ...

  9. Android悬浮窗适配全机型,包含8.0,小米魅族华为悬浮窗权限适配demo看这一篇就够了

    机型多杂,适配无法完全兼容,不如换种实现方式,性能比悬浮窗好,不需要权限,效果更好:https://blog.csdn.net/m0_38058826/article/details/10399339 ...

  10. Android悬浮窗开启 适配所有机型(附源码)

    Android悬浮窗开启 适配所有机型(附源码) 1.开启悬浮窗权限 清单文件中添加: <uses-permission android:name="android.permissio ...

最新文章

  1. 比特币核心概念及算法
  2. C++11多线程编程-两个进程轮流打印1~100
  3. Eclipse Alt+/ Content Assistant
  4. 输入一个数3256,将他从小到大输出,就是2356
  5. hdoj 1257(暴力)
  6. oracle 052 题库更新,OCP题库升级,新版052考试题及答案整理-18
  7. K8S_Google工作笔记0012---通过二进制方式_部署master组件
  8. 电脑系统怎么重装?U盘安装Windows XP系统保姆级教程
  9. DayDayUp:2020,再见了,不平凡的一年,让我懂得了珍惜,让我明白了越努力越幸运
  10. QT软件开发: 基于QT设计的完整版视频播放器、多媒体播放器(mdk-sdk)
  11. html实现读取读卡器,如何在web浏览器页面使用IC卡读卡器并且兼容所有浏览器
  12. swoole-redis连接池的问题总结
  13. 调用C# System.Drawing 画图
  14. 2022DASCTF Apr X FATE 防疫挑战赛 部分web复现
  15. Unity(四十三):存档、文本文件读写
  16. 2019最新网易云课堂人工智能数学基础(同步更新)
  17. 骚年 你还太弱,请专心练剑
  18. 智能公交系统电子站牌设计
  19. uniapp微信小程序canvas生成简单海报并下载
  20. ps之制作电影海报灵感网站

热门文章

  1. 目前绝大多数处理语言先验性文章总结
  2. ReadTimeoutError: HTTPSConnectionPool(host='files.pythonhosted.org', port=443): Read timed out.
  3. 未来的计算机儿童画,儿童画未来的科学幻想绘画优秀作品
  4. MFC CFile操作类介绍
  5. idea maven路径总是自己改成默认的路径C:\Users\Ad\.m2\repository
  6. 白光干涉仪如何获得高度信息丨科普篇
  7. Wowza 的Http扩展 (Publish State)
  8. react04-Ref与Hook
  9. STM32L031 HAL库读写内部EEprom
  10. Python:实现quantum entanglement量子纠缠技术算法(附完整源码)