Android 悬浮窗
本文参考文章地址:https://juejin.cn/post/7009180088310693919
一、申请权限
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
二、创建悬浮窗service
<serviceandroid:name=".FloatingWindowService"android:enabled="true"android:exported="true">
</service>
三、悬浮窗布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><FrameLayoutandroid:id="@+id/layout_drag"android:layout_width="match_parent"android:layout_height="15dp"android:background="#dddddd"><androidx.appcompat.widget.AppCompatImageViewandroid:id="@+id/iv_close"android:layout_width="15dp"android:layout_height="15dp"android:background="#111111"android:layout_gravity="end" /></FrameLayout><androidx.appcompat.widget.AppCompatTextViewandroid:id="@+id/tv_content"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_gravity="center_horizontal"android:background="#eeeeee"android:scrollbars="vertical" />
</LinearLayout>
四、悬浮窗设置
private lateinit var windowManager: WindowManager
private lateinit var layoutParams: WindowManager.LayoutParams
private lateinit var tvContent: AppCompatTextView
private var floatingView: View? = null
private val stringBuilder = StringBuilder()
private var x = 0
private var y = 0// 获取windowManager并设置layoutParamswindowManager = getSystemService(WINDOW_SERVICE) as WindowManagerlayoutParams = WindowManager.LayoutParams().apply {type = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY} else {WindowManager.LayoutParams.TYPE_PHONE}gravity = Gravity.START or Gravity.TOPflags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLEwidth = 300height = 500}if (Settings.canDrawOverlays(this)) {//新建悬浮窗事件floatingView = LayoutInflater.from(this).inflate(R.layout.layout_float_view, null)//文字显示控件tvContent = floatingView!!.findViewById(R.id.tv_content)//关闭悬浮窗floatingView!!.findViewById<AppCompatImageView>(R.id.iv_close).setOnClickListener {windowManager.removeView(floatingView)}// 设置TextView滚动tvContent.movementMethod = ScrollingMovementMethod.getInstance()//设置悬浮窗移动floatingView!!.findViewById<FrameLayout>(R.id.layout_drag).setOnTouchListener { _, event ->when (event.action) {MotionEvent.ACTION_DOWN -> {x = event.rawX.toInt()y = event.rawY.toInt()}MotionEvent.ACTION_MOVE -> {val currentX = event.rawX.toInt()val currentY = event.rawY.toInt()val offsetX = currentX - xval offsetY = currentY - yx = currentXy = currentYlayoutParams.x = layoutParams.x + offsetXlayoutParams.y = layoutParams.y + offsetYwindowManager.updateViewLayout(floatingView, layoutParams)}}true}windowManager.addView(floatingView, layoutParams)
}
五、通过广播联调显示悬浮窗
全部代码如下
class MainActivity : AppCompatActivity() {private lateinit var buttonSend: Buttonprivate lateinit var buttonView: Buttonprivate val TAG = "MainActivity"@SuppressLint("MissingInflatedId", "UnspecifiedRegisterReceiverFlag")override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)buttonSend = findViewById(R.id.buttonClick)buttonSend.setOnClickListener {sendMessage()}buttonView = findViewById(R.id.buttonView)buttonView.setOnClickListener {startWindow()}}//发送广播到悬浮窗private fun sendMessage() {Intent("android.intent.action.MyReceiver").apply {putExtra("content", "float view test!")sendBroadcast(this)}}//检查悬浮窗权限是否打开,若没有打开则打开系统设置页面private fun startWindow() {if (!Settings.canDrawOverlays(this)) {startActivityForResult(Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,Uri.parse("package:$packageName")), 0)} else {startService(Intent(this, FloatingWindowService::class.java))}}//请求权限override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {super.onActivityResult(requestCode, resultCode, data)if (requestCode == 0) {if (Settings.canDrawOverlays(this)) {Toast.makeText(this, "悬浮窗权限授权成功", Toast.LENGTH_SHORT).show()startService(Intent(this, FloatingWindowService::class.java))}}}
}class FloatingWindowService : Service() {private lateinit var windowManager: WindowManagerprivate lateinit var layoutParams: WindowManager.LayoutParamsprivate lateinit var tvContent: AppCompatTextViewprivate lateinit var handler: Handlerprivate var receiver: ViewReceiver? = nullprivate var floatingView: View? = nullprivate val stringBuilder = StringBuilder()private var x = 0private var y = 0private var floatView = false@SuppressLint("UnspecifiedRegisterReceiverFlag")override fun onCreate() {super.onCreate()// 注册广播receiver = ViewReceiver()val filter = IntentFilter()filter.addAction("android.intent.action.MyReceiver")registerReceiver(receiver, filter);// 获取windowManager并设置layoutParamswindowManager = getSystemService(WINDOW_SERVICE) as WindowManagerlayoutParams = WindowManager.LayoutParams().apply {type = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY//显示于所有应用之上} else {WindowManager.LayoutParams.TYPE_PHONE}gravity = Gravity.START or Gravity.TOPflags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLEwidth = 300height = 500}handler = Handler(this.mainLooper) { msg ->tvContent.text = msg.obj as String// 当文本超出屏幕自动滚动,保证文本处于最底部val offset = tvContent.lineCount * tvContent.lineHeightfloatingView?.apply {if (offset > height) {tvContent.scrollTo(0, offset - height)}}false}}override fun onBind(intent: Intent?): IBinder? {return null}@SuppressLint("ClickableViewAccessibility")override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {if (Settings.canDrawOverlays(this)) {//新建悬浮窗事件floatingView = LayoutInflater.from(this).inflate(R.layout.layout_float_view, null)//文字显示控件tvContent = floatingView!!.findViewById(R.id.tv_content)//关闭悬浮窗floatingView!!.findViewById<AppCompatImageView>(R.id.iv_close).setOnClickListener {stringBuilder.clear()windowManager.removeView(floatingView)floatView = false}// 设置TextView滚动tvContent.movementMethod = ScrollingMovementMethod.getInstance()//设置悬浮窗移动floatingView!!.findViewById<FrameLayout>(R.id.layout_drag).setOnTouchListener { _, event ->when (event.action) {MotionEvent.ACTION_DOWN -> {x = event.rawX.toInt()y = event.rawY.toInt()}MotionEvent.ACTION_MOVE -> {val currentX = event.rawX.toInt()val currentY = event.rawY.toInt()val offsetX = currentX - xval offsetY = currentY - yx = currentXy = currentYlayoutParams.x = layoutParams.x + offsetXlayoutParams.y = layoutParams.y + offsetYwindowManager.updateViewLayout(floatingView, layoutParams)}}true}windowManager.addView(floatingView, layoutParams)floatView = true}return super.onStartCommand(intent, flags, startId)}override fun onDestroy() {// 注销广播并删除浮窗unregisterReceiver(receiver)receiver = nullif (floatView) {windowManager.removeView(floatingView)}}inner class ViewReceiver : BroadcastReceiver() {override fun onReceive(context: Context, intent: Intent) {val content = intent.getStringExtra("content") ?: ""stringBuilder.append(content).append("\n")val message = Message.obtain()message.what = 0message.obj = stringBuilder.toString()handler.sendMessage(message)}}
}
相关文章:
Android 悬浮窗
本文参考文章地址:https://juejin.cn/post/7009180088310693919 一、申请权限 <uses-permission android:name"android.permission.SYSTEM_ALERT_WINDOW" />二、创建悬浮窗service <serviceandroid:name".FloatingWindowService"an…...

3.物联网射频识别,(高频)RFID应用ISO14443-2协议
一。ISO14443-2协议简介 1.ISO14443协议组成及部分缩略语 (1)14443协议组成(下面的协议简介会详细介绍) 14443-1 物理特性 14443-2 射频功率和信号接口 14443-3 初始化和防冲突 (分为Type A、Type B两种接口&…...
数据分析笔记1
数据分析概述:数据获取--探索分析与可视化--预处理--分析建模--模型评估 数据分析含义:利用统计与概率的分析方法提取有用的信息,最后进行总结与概括 一、数据获取 实用网站:kaggle 阿里云天池 数据仓库:将所有业务数据…...
paramiko 3
import paramiko import concurrent.futuresdef execute_remote_command(hostname, username, password, command):try:# 创建SSH客户端client paramiko.SSHClient()client.set_missing_host_key_policy(paramiko.AutoAddPolicy())# 使用密码认证连接远程主机client.connect(h…...
基于Dlib训练自已的人脸数据集提高人脸识别的准确率
前言 由于图像的质量、光线、角度等因素影响。这时如果使用官方提供的模型做人脸识别,就会导至识别率不是很理想。人脸识别的准确率与图像的清晰度和质量有关。如果图像模糊、光线不足或者有其他干扰因素,Dlib 可能无法正确地识别人脸。为了确保图像质量…...
Git 详细安装教程(详解 Git 安装过程的每一个步骤
Git 详细安装教程(详解 Git 安装过程的每一个步骤) 该文章详细具体,值得收藏学习...
kafka伪集群部署,使用KRAFT模式
1:拉去管理kafka界面UI镜像 docker pull provectuslabs/kafka-ui2:拉去管理kafka镜像 docker pull bitnami/kafka3:docker-compose.yml version: 3.8 services:kafka-1:container_name: kafka1image: bitnami/kafka ports:- "19092:19092"- "19093:19093&quo…...
【双指针遍历】N数之和问题
文章目录 二数之和LC1三数之和LC15四数之和LC18最接近的三数之和LC16 二数之和LC1 题目链接 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。 你可以假设每种输入只会对…...
Qt的QObject类
文章目录 QObject类如何在Qt中使用QObject的信号与槽机制?如何在Qt中使用QObject的属性系统?QObject的元对象系统如何实现对象的反射功能? QObject类 Qt的QObject类是Qt框架中的基类,它是所有Qt对象的父类。QObject提供了一些常用…...

【图论C++】链式前向星(图(树)的存储)
/*** file * author jUicE_g2R(qq:3406291309)————彬(bin-必应)* 一个某双流一大学通信与信息专业大二在读 * * brief 一直在竞赛算法学习的路上* * copyright 2023.9* COPYRIGHT 原创技术笔记:转载需获得博主本人…...

16.PWM输入捕获示例程序(输入捕获模式测频率PWMI模式测频率和占空比)
目录 输入捕获相关库函数 输入捕获模式测频率 PWMI模式测频率和占空比 两个代码的接线图都一样,如下 测量信号的输入引脚是PA6,信号从PA6进来,待测的PWM信号也是STM32自己生成的,输出引脚是PA0。 需要配置电路连接图示如下&…...

pip version 更新
最近报了一个错: 解决办法: 在cmd输入“conda install pip” conda install pip 完了之后再输入: python -m pip install --upgrade pip ok....

Oracle - 多区间按权重取值逻辑
啰嗦: 其实很早就遇到过类似问题,也设想过,不过一致没实际业务需求,也就耽搁了;最近有业务提到了,和同事讨论,各有想法,所以先把逻辑整理出来,希望有更好更优的解决方案;…...
本次CTF·泰山杯网络安全的基础知识部分(二)
简记23年九月参加的泰山杯网络安全的部分基础知识的题目,随时补充 15(多选)网络安全管理工作必须坚持“谁主管、谁负责,谁运营、谁负责,谁使用、谁负责”的原则,和“属地管理”的原则 谁主管、谁负责&…...

MyBatis 映射文件(Mapper XML):配置与使用
MyBatis 映射文件(Mapper XML):配置与使用 MyBatis是一个强大的Java持久化框架,它允许您将SQL查询、插入、更新和删除等操作与Java方法进行映射。这种映射是通过MyBatis的映射文件,通常称为Mapper XML文件来实现的。本…...

基于 SpringBoot 的大学生租房网站
文章目录 1 简介2 技术栈3 需求分析4 系统设计5 系统详细设计5.1系统功能模块5.2管理员模块5.3房主功能模块5.4用户功能模块 源码咨询 1 简介 本大学生租房系统使用简洁的框架结构,专门用于用户浏览首页,房屋信息,房屋评价,公告资…...

BL808学习日志-0-概念理解
一、主核心的介绍 1.三个核心在FREERTOS系统中相互独立,各负责各自的外设和程序;其中M0和LP核心在一个总线上,D0单独在一个总线上,两个总线使用AXI4.0(??)通讯? CPU0(M0)-E907架构,320MHz; CPU1(LP)-E9…...
CISSP学习笔记:业务连续性计划
第三章 业务连续性计划 3.1 业务连续性计划 业务连续性计划(BCP): 对组织各种过程的风险评估,发生风险的情况下为了使风险对组织的影响降至最小而定制的各种计划BCP和DRP首先考虑的人不受伤害,然后再解决IT恢复和还原问题BCP的主要步骤: 项…...
.NET Nuget包推荐安装
文章目录 前言通用WPFWebApiBlazor 前言 我这里的包主要是.NET Core的,.NET Framework可能不支持。 通用 Newtonsoft.Json:最常用的C#和Json对象互转的包。支持匿名对象,但是不支持Enum枚举类型,显示的是Enum的数值,…...

【文献阅读】Pocket2Mol : 基于3D蛋白质口袋的高效分子采样 + CrossDocked数据集说明
Pocket2Mol: Efficient Molecular Sampling Based on 3D Protein Pockets code: GitHub - pengxingang/Pocket2Mol: Pocket2Mol: Efficient Molecular Sampling Based on 3D Protein Pockets 所用数据集 与“A 3D Generative Model for Structure-Based Drug Desi…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...
<6>-MySQL表的增删查改
目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
#Uniapp篇:chrome调试unapp适配
chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...

push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...

android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...

AI语音助手的Python实现
引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...

Linux中《基础IO》详细介绍
目录 理解"文件"狭义理解广义理解文件操作的归类认知系统角度文件类别 回顾C文件接口打开文件写文件读文件稍作修改,实现简单cat命令 输出信息到显示器,你有哪些方法stdin & stdout & stderr打开文件的方式 系统⽂件I/O⼀种传递标志位…...