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…...
bittorrent-tracker与WebTorrent生态:现代浏览器P2P下载的终极指南 [特殊字符]
bittorrent-tracker与WebTorrent生态:现代浏览器P2P下载的终极指南 🌊 【免费下载链接】bittorrent-tracker 🌊 Simple, robust, BitTorrent tracker (client & server) implementation 项目地址: https://gitcode.com/gh_mirrors/bit/…...
自动驾驶卡车软件平台:技术架构、商业模式与商业化落地解析
1. 自动驾驶卡车软件平台全景解析最近几年,自动驾驶卡车这个赛道真是热闹非凡,感觉每周都有新融资、新合作或者新路测的消息出来。作为一个在汽车电子和软件行业摸爬滚打了十几年的老工程师,我一直在密切关注这个领域的动态。自动驾驶卡车&am…...
大模型上下文长度对Agent的影响:从4K到1M的质变
目录大模型上下文长度对Agent的影响:从4K到1M的质变引言:工作台革命一、上下文窗口演进史:从4K到1M的百倍跃迁1.1 时间线上的技术里程碑1.2 为什么2025年成为“百万Token元年”?二、长上下文的质变:Agent能力的三重跃迁…...
基于MCP协议构建AI助手业务工具适配器:从原理到实践
1. 项目概述:用MCP协议为AI助手装上“业务之眼”如果你和我一样,日常开发中需要频繁地在Stripe看支付数据、在Sentry查线上错误、在Notion里翻文档、在Linear跟进任务状态,那你一定懂那种在十几个浏览器标签页和不同SaaS平台间反复横跳的疲惫…...
基于Vue 3与UnoCSS构建轻量级个人导航页:从零部署到高级定制
1. 项目概述:一个轻量级、可定制的个人导航页 最近在折腾自己的浏览器主页,厌倦了那些臃肿、广告满天飞的默认页面,也受够了每次都要在书签栏里翻找常用链接。作为一个喜欢把一切工具都“私有化”和“个性化”的开发者,我决定自己…...
松下绿色科技战略:技术复用与协同效应如何驱动企业转型
1. 松下困局:消费电子巨头的十字路口2013年初的拉斯维加斯,消费电子展(CES)的喧嚣与霓虹之下,松下的时任社长津贺一宏站在聚光灯前,面对的却是一个冰冷而残酷的现实:公司预计将连续第二年录得高…...
2篇3章3节:Trae 的高效小说创作与文件管理实操
在人工智能辅助小说创作的过程中,工具操作方式、内容生成逻辑与文件管理体系,直接决定写作效率与文稿质量。Trae作为适配小说创作的专业工具,不仅支持单章、全章智能化生成正文内容,适配短篇、长篇不同创作场景,还具备多屏拆分、标签页管理、规范化文件收纳等实用功能。熟…...
VisualCppRedist AIO:一站式解决Windows应用程序运行库缺失难题
VisualCppRedist AIO:一站式解决Windows应用程序运行库缺失难题 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 在Windows系统中,你是否经…...
动物森友会岛屿设计终极指南:用Happy Island Designer轻松规划你的梦想岛屿
动物森友会岛屿设计终极指南:用Happy Island Designer轻松规划你的梦想岛屿 【免费下载链接】HappyIslandDesigner "Happy Island Designer (Alpha)",是一个在线工具,它允许用户设计和定制自己的岛屿。这个工具是受游戏《动物森友会…...
管式土壤墒情监测站:深埋地下测湿度,云端上报助灌溉
管式土壤墒情监测站采用土壤介电常数检测原理,结合专业数学模型算法,搭配独创螺旋式测量电极结构开展高精度土壤含水率监测。土壤介电常数与土壤含水量存在稳定且精准的对应关系,设备通过传感器高频感知土层介电参数变化,经内置算…...
