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…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...
图表类系列各种样式PPT模版分享
图标图表系列PPT模版,柱状图PPT模版,线状图PPT模版,折线图PPT模版,饼状图PPT模版,雷达图PPT模版,树状图PPT模版 图表类系列各种样式PPT模版分享:图表系列PPT模板https://pan.quark.cn/s/20d40aa…...
听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...
GitHub 趋势日报 (2025年06月06日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...
Web中间件--tomcat学习
Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机,它可以执行Java字节码。Java虚拟机是Java平台的一部分,Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...
