Android 应用弹出悬浮窗

news2024/12/26 23:25:43

Android开发者经常遇到应用想弹出悬浮窗的操作,而且有可能还想要高层级弹窗,就像ipone的浮标touch一样。android当然也有类似的悬浮图标,比如前些年我们的流量监控提醒。

 这里我们忽略UI美学,简单记录一下:

1、基本使用

它的基本使用步骤是不会变的,只是有时候我们可能根据不同需求会改变它样式的参数,首先记得在 manifests.xml 清单文件中添加权限,然后根据需要申请权限,如果是系统级应用,可以让系统工程师配置赋予我们的应用权限:

    <!-- 允许程序添加悬浮窗 -->
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
if (!Settings.canDrawOverlays(this)) {
            Logger.d("onCreate: canDrawOverlays false.");
            Intent intent = new Intent();
            intent.setAction(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
            startActivity(intent);
        }else {
            Logger.d("onCreate: canDrawOverlays true.");
            showWindowView();
        }

具体的怎么添加呢:

    private void showWindowView(){
         //Activity中的方法,得到窗口管理器
        mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        //设置悬浮窗布局属性
        WindowManager.LayoutParams mWindowLayoutParams = new WindowManager.LayoutParams();
        //设置类型,具体有哪些值可取在后面附上
    // 设置窗体显示类型
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        mWindowLayoutParams.type =WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
    } 
    else {
        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;
        //设置悬浮窗的宽度
        mWindowLayoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
        //设置悬浮窗的高度
        mWindowLayoutParams.height = 200;
        //设置悬浮窗的布局
        LinearLayout linearLayout = new LinearLayout(this);
        linearLayout.setBackgroundColor(Color.GRAY);
        TextView textView = new TextView(this);
        textView.setTextColor(getColor(R.color.white_16p));
        textView.setTextSize(32);
        textView.setGravity(Gravity.CENTER);
        textView.setText("测试浮窗");
        LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
        linearLayout.addView(textView, layoutParams);
        //加载显示悬浮窗
        mWindowManager.addView(linearLayout, mWindowLayoutParams);
    }

注释中提到悬浮窗只要不消失,屏幕方向就会一直保持,如果设置悬浮窗横屏,将程序退到后台时,则手机桌面也会横屏,看起来就会很不舒服,所以如果不是特定需求,我们可以在 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的异常,所以在添加悬浮窗之前最好先判断一下该悬浮窗是否已添加:

if (linearLayout.isAttachedToWindow())

2、type 和 flags 可取值

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;

这个值我也不是每个都试过,所以具体效果会有什么不同不能妄言。感兴趣的可以都尝试一下。

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;

暂时记录一下吧,遇到的时候方便查一下。当然,这些实际上Android开发者官网源码里都能看到。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/602955.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

mac os 安装rz/sz

说明&#xff1a;使用rz sz实现终端的文件传输&#xff0c;该命令主要使用场景为 macos中通过堡垒机登陆后无法使用ftp工具传输文件。 工具&#xff1a;iTerm2、lrzsz、homebrew 以及两个脚本文件&#xff08;iterm2-recv-zmodem.sh、iterm2-send-zmodem.sh&#xff09; …

基于确定有穷自动机(DFA算法)实现敏感词过滤

1.DFA算法简介 DFA(Deterministic Finite Automaton) 是一种非递归自动机&#xff0c;也称为确定有穷自动机。它是通过event和当前的state得到nextstate&#xff0c;即eventstatenextstate。 确定&#xff1a;状态以及引起状态转换的事件都是可确定的。 有穷&#xff1a;状态以…

EBU6304 Software Engineering 知识点总结_4 analysis, design, implementation, testing

analysis 仅仅从用户的需求来看得到的消息不全面&#xff0c;还需要分析。用户可能认为你明白了&#xff0c;或者他考虑不全面&#xff0c;觉得一些地方是不需要的。 因此我们需要分析来 Refining requirements。 gather requirements-analyse in real world context-develo…

(字符串 ) 剑指 Offer 58 - II. 左旋转字符串 ——【Leetcode每日一题】

❓剑指 Offer 58 - II. 左旋转字符串 难度&#xff1a;简单 字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如&#xff0c;输入字符串"abcdefg"和数字2&#xff0c;该函数将返回左旋转两位得到的…

Codeforces Round 875 (Div. 2)

Problem - D - Codeforces 思路&#xff1a; 注意到bibj<2*n&#xff0c;所以ai*aj<2*n&#xff0c;即我们实际只需要枚举个a的匹配即可为了不重不漏&#xff0c;我们可以枚举x从1到&#xff0c;寻找所有与x匹配且大于等于x的[a,b]对这样复杂度就是 #include <bits…

OpenCV笔记整理【人脸检测之Harr级联分类器dlib库】

1. 级联分类器&#xff1a; OpenCV提供的级联分类器有Harr、HOG、LBP这3种&#xff0c;这些分类器以XML文件保存&#xff0c;这里主要演示Harr检测人脸&#xff08;OpenCV提供的分类器不仅限于检测人脸&#xff0c;还包括下表特征检测&#xff0c;当然OpenCV还支持训练自己的级…

Vim学习笔记【Ch02】

Vim学习笔记 系列笔记链接Ch02 Buffers, Windows, TabsBuffers什么是buffer查看所有bufferbuffer之间的切换删除buffer退出所有窗口 Windows窗口的创建窗口切换快捷键其他快捷键 Tabs什么是tabtab相关命令 window和buffer结合的3D移动小结 系列笔记链接 Ch00&#xff0c;Ch01 …

python介绍——入门

前言 Python 是一种面向对象的解释型计算机程序设计语言&#xff0c;它继承了传统编译语言的强大性和通用性&#xff0c;同时也借鉴了脚本语言和解释语言的易用性。今天我就来给大家简单介绍一下python&#xff1a; 一、python的起源 1989年的圣诞节期间&#xff0c;吉多▪范…

Redis底层学习(二)—存储类型-String篇

这里写目录标题 应用场景底层结构知识普及 应用场景 服务器命令&#xff1a; 1.单值缓存 存储key,value &#xff1a;SET key value2.对象缓存 存储key,value :SET key value&#xff08;json 格式数据&#xff09; 3.分布式锁 底层结构 我们可以通过命令查看 value…

C++ 学习 ::【基础篇:14】:C++ 类的基本成员函数:析构函数的作用 及 自定义析构函数情形

本系列 C 相关文章 仅为笔者学习笔记记录&#xff0c;用自己的理解记录学习&#xff01;C 学习系列将分为三个阶段&#xff1a;基础篇、STL 篇、高阶数据结构与算法篇&#xff0c;相关重点内容如下&#xff1a; 基础篇&#xff1a;类与对象&#xff08;涉及C的三大特性等&#…

scratch找食物 中国电子学会图形化编程 少儿编程 scratch编程等级考试一级真题和答案解析2023年5月

目录 scratch找食物 一、题目要求 1、准备工作 2、功能实现 二、案例分析

全志V3S嵌入式驱动开发(多按键输入驱动)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 前面我们说过&#xff0c;荔枝派的开发板上面&#xff0c;有4个按键本身不是通过gpio连接到soc上面的。它是通过ad的方法&#xff0c;连接到主芯片…

SpringCloud GateWay-Filter学习

3 Filter/过滤器 文章目录 3 Filter/过滤器1 GatewayFilter 使用 -- 路由过滤器2 GatewayFilter 使用 -- 自定义过滤器 路由过滤器可用于修改进入的HTTP请求和返回的HTTP响应Spring Cloud Gateway 内置了多种路由过滤器&#xff0c;他们都由GatewayFilter的工厂类来产生 1 Gat…

华为OD机试真题B卷 Java 实现【IPv4地址转换成整数】,附详细解题思路

一、题目描述 存在一种虚拟 IPv4 地址&#xff0c;由4小节组成&#xff0c;每节的范围为0~255&#xff0c;以#号间隔&#xff0c; 虚拟 IPv4 地址可以转换为一个32位的整数&#xff0c;例如&#xff1a; 128#0#255#255&#xff0c;转换为32位整数的结果为2147549183&#xff0…

以技术实践赋能开源安全|2023开放原子全球开源峰会开源安全技术与实践分论坛即将启幕

作为数字化转型时代的重要技术和协作模式&#xff0c;开源软件在各行各业得到广泛应用&#xff0c;由此也引发了诸多与安全相关的问题。6月12日&#xff0c;2023开放原子全球开源峰会“开源安全技术与实践”分论坛将在北京经开区北人亦创国际会展中心举行。 本次分论坛由开放原…

为什么说 Go 语言字符串是不可变的?

原文链接&#xff1a; 为什么说 Go 语言字符串是不可变的&#xff1f; 最近有读者留言说&#xff0c;平时在写代码的过程中&#xff0c;是会对字符串进行修改的&#xff0c;但网上都说 Go 语言字符串是不可变的&#xff0c;这是为什么呢&#xff1f; 这个问题本身并不困难&am…

SAP-QM-物料主数据-质量管理视图字段解析

过账到质检库存&#xff1a;要勾选&#xff0c;否则收货后库存不进入质检库存HU检验&#xff1a;收货到启用HU管理的库位时产生检验批&#xff0c;例如某个成品物料是收货到C002库位&#xff0c;该库位启用了HU管理&#xff0c;那么此处要勾选。但是如果勾选了&#xff0c;却收…

30天学会vue.js?|vue.js 3 移动应用开发实战 阅读笔记

最近又在折腾vuejs, 计划用30天的时间来掌握这个前端语言。 大概用了一周时间看完这本书。 这本书需要有编程基础的同学阅读。如果从零开始学前端的话&#xff0c;个人不建议&#xff0c;书本内容跳跃性很大&#xff0c;甚至个人觉得有点凌乱。PS&#xff1a;阅读此书一定要配…

黑马Redis视频教程实战篇(五)

目录 一、达人探店 1.1、发布探店笔记 1.2、查看探店笔记 1.3、点赞功能 1.4、点赞排行榜 二、好友关注 2.1、关注和取消关注 2.2、共同关注 2.3、Feed流实现方案 2.4、推送到粉丝收件箱 2.4、实现分页查询收邮箱 一、达人探店 1.1、发布探店笔记 发布探店笔记 探…

自定义组件和样式学习

一、使用组件3步 例如&#xff1a;APP.vue中使用另外两个组件Left.vue,Right.vue &#xff08;3个页面&#xff09; 1.在APP.vue中用import *** from **** 导入Left.vue、Right.vue页面 2.在APP.vue的js中和data同级注册&#xff0c;components{Left,Rirght} 3.注册完后可在APP…