Android之悬浮窗实现

文章目录

  • 前言
  • 一、效果图
  • 二、实现步骤
    • 1.AndroidManifest权限以及service注册
    • 2.service代码
    • 3.activity实现
  • 总结


前言

经常接触音视频以及直播的同学应该知道,悬浮窗是必备需求,今天就记录一下自己悬浮窗的视线过程,流程就是点击缩小按钮回到桌面,把悬浮窗放桌面,点击悬浮窗回到应用界面。


一、效果图

效果图一张为正常界面,一张为悬浮窗效果界面。
在这里插入图片描述
在这里插入图片描述

二、实现步骤

1.AndroidManifest权限以及service注册

代码如下(示例):

    <!--悬浮窗--><uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /><uses-permission android:name="android.permission.FOREGROUND_SERVICE" /><!-- 悬浮窗Service --><serviceandroid:name=".service.FloatingWindowService"android:enabled="true"android:exported="false"/>

2.service代码

代码如下(示例):

/*** @Author : CaoLiulang* @Time : 2025/3/18 13:22* @Description :悬浮窗service*/
public class FloatingWindowService extends Service {private WindowManager windowManager;private View floatingView;private ScheduledExecutorService executor;// 定义变量记录初始触摸点和窗口初始位置private float initialTouchX, initialTouchY;private float startX; // 声明为成员变量private float startY;@Overridepublic void onCreate() {super.onCreate();executor = Executors.newSingleThreadScheduledExecutor();createFloatingWindow();}private void createFloatingWindow() {// 引入悬浮窗口布局floatingView = LayoutInflater.from(this).inflate(R.layout.livestreamingconsolesx, null);windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);// 窗口参数设置WindowManager.LayoutParams params = new WindowManager.LayoutParams(380,  // 显式设置宽度(像素)600,  // 显式设置高度(像素)Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY :WindowManager.LayoutParams.TYPE_PHONE,WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,PixelFormat.TRANSLUCENT);params.gravity = Gravity.START | Gravity.TOP;params.x = 20;params.y = 20;windowManager.addView(floatingView, params);floatingView.setOnTouchListener((v, event) -> {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:initialTouchX = event.getRawX() - params.x;initialTouchY = event.getRawY() - params.y;startX = event.getRawX();startY = event.getRawY();break;case MotionEvent.ACTION_MOVE:float newX = event.getRawX() - initialTouchX;float newY = event.getRawY() - initialTouchY;// 获取屏幕尺寸WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);DisplayMetrics metrics = new DisplayMetrics();if (wm != null) {wm.getDefaultDisplay().getMetrics(metrics);int screenWidth = metrics.widthPixels;int screenHeight = metrics.heightPixels;// 限制移动范围newX = Math.max(0, Math.min(newX, screenWidth - params.width));newY = Math.max(0, Math.min(newY, screenHeight - params.height));}params.x = (int) newX;params.y = (int) newY;windowManager.updateViewLayout(floatingView, params);return true;case MotionEvent.ACTION_UP:// 计算移动距离float deltaX = Math.abs(event.getRawX() - startX);float deltaY = Math.abs(event.getRawY() - startY);// 如果移动距离小于阈值,视为点击if (deltaX < 5 && deltaY < 5) {// 手动触发点击事件floatingView.performClick();}return true;}return false;});// 单独设置 OnClickListenerfloatingView.setOnClickListener(v -> {// 点击逻辑  这里是跳转本软件,有的手机会重启,所以直接选择下面方式跳转当前界面//Intent intent = getPackageManager().getLaunchIntentForPackage("这里就是自己的包名");//if (intent != null) {//intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);// startActivity(intent);//}//跳转当前界面Intent intent = new Intent(this, LiveStreamingConsole.class);intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);startActivity(intent);//延迟一秒关闭executor.schedule(() -> stopSelf(), 1, TimeUnit.SECONDS);});}@Overridepublic void onDestroy() {super.onDestroy();// 关闭线程池(根据实际情况选择是否立即关闭)executor.shutdownNow();if (floatingView != null) windowManager.removeView(floatingView);}@Nullable@Overridepublic IBinder onBind(Intent intent) {return null;}
}

3.activity实现

//定义变量
private var YOUR_REQUEST_CODE = 1000
//调用 动态判断权限if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {if (!Settings.canDrawOverlays(this)) {val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,Uri.parse("package:$packageName"))startActivityForResult(intent, YOUR_REQUEST_CODE)} else {createFloatingWindow();}}@RequiresApi(Build.VERSION_CODES.O)private fun createFloatingWindow() {//启动servicestartService(Intent(this, FloatingWindowService::class.java))// 返回桌面moveTaskToBack(true)}@RequiresApi(Build.VERSION_CODES.O)override fun onActivityResult(requestCode: Int, resultCode: Int, @Nullable data: Intent?) {super.onActivityResult(requestCode, resultCode, data)if (requestCode == YOUR_REQUEST_CODE) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Settings.canDrawOverlays(this)) {createFloatingWindow()} else {Toast.makeText(this, "需要悬浮窗权限", Toast.LENGTH_SHORT).show()}}}

总结

提示:service里面的布局文件就是悬浮窗的布局,所以xml我就没有贴代码,测试的时候可以自己随意画个xml看效果:

以上就是Android悬浮窗的实现了,service中还可以交互数据,也就是悬浮窗,欢迎各位同学指出问题。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

25.单例模式实现线程池

一、线程池的概念 1.1 线程池的介绍 线程池是一种线程使用模式。线程过多会带来调度开销&#xff0c;进而影响缓存局部性和整体性能。而线程池维护着多个线程&#xff0c;等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅…

基于springboot的免税商品优选购物商城(020)

摘 要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff0c;免税商品优选购物商城当然也不能排除在外&#xff0c;随着购物商城的不断成熟&#xff0c;它彻底改变了过去传统的免税商品优选购物商城方式&…

RIP路由欺骗攻击与防御实验详解

一、基础网络配置 1. 路由器R1配置 interface GigabitEthernet0/0/0ip address 192.1.2.254 255.255.255.0 ! interface GigabitEthernet0/0/1ip address 192.1.3.254 255.255.255.0 ! router rip 1version 2network 192.1.2.0network 192.1.3.0 2. 路由器R2配置 interface…

整理和总结微信小程序的高频知识点

前言 近期萌生了一些想法&#xff0c;感觉可以做一个小程序作为产出。 但小程序做得比较少&#xff0c;因此边做边复习。整理和总结了一些高频知识点和大家一起分享。 一、模板和组件 1.1模板&#xff08;Template&#xff09; 优势 简单灵活&#xff1a;模板定义和使用都较…

如何检查CMS建站系统的插件是否安全?

检查好CMS建站系统的插件安全是确保网站安全的重要环节&#xff0c;对于常见的安全检查&#xff0c;大家可以利用以下几种有效的方法和工具&#xff0c;来帮你评估插件的安全性。 1. 检查插件来源和开发者信誉 选择可信来源&#xff1a;仅从官方插件库或可信的第三方开发者处…

RAG优化:利用python实现上下文感知(扩展)增强检索效果

检索增强生成(RAG)通过从外部知识源检索相关信息来增强AI的响应能力。传统的检索方法通常返回孤立的文本片段,这可能导致回答不完整。 为了解决这个问题,我们引入了基于上下文的检索方法,确保检索到的信息包含相邻的文本片段,以提高回答的连贯性。 通过结合重叠分块、上…

在 macOS Sequoia 15.2 中启用「三指拖动」并实现快速复制的完整指南 ✨

在 macOS Sequoia 15.2 中启用「三指拖动」并实现快速复制的完整指南 &#x1f34e;✨ 适用系统&#xff1a;macOS Sequoia 版本15.2 及以上 一、功能简介 &#x1f31f; 通过「三指拖动」手势&#xff0c;你可以轻松完成以下操作&#xff1a; • 移动文件/文本&#xff1a;直…

LeetCode 2614.对角线上的质数:遍历(质数判断)

【LetMeFly】2614.对角线上的质数&#xff1a;遍历(质数判断) 力扣题目链接&#xff1a;https://leetcode.cn/problems/prime-in-diagonal/ 给你一个下标从 0 开始的二维整数数组 nums 。 返回位于 nums 至少一条 对角线 上的最大 质数 。如果任一对角线上均不存在质数&…

基于Java(Springboot+Gradle+Mybatis+templeaf 框架)+Mysql构建的(Web)校园二手平台系统

二手市场 1 系统分析 1.1 需求分析 项目背景 国内最大的二手服务商“易趣、淘宝”其注册用户有 61% 为在校大学生&#xff0c;其他占 25% 为社会人士注册&#xff0c;他们每年与学生的交易量占总交易量的 85% 以上. “易淘”均不向交易双方任何用户提供商品质保和售后服务…

ue5蓝图项目转换为c++项目 遇到的问题

蓝图项目转c项目 工具/新建C类&#xff0c;随便新建一个c类&#xff0c;即可从蓝图项目转换为c项目 如果转换正常&#xff0c;UE5会要求重新编译程序&#xff0c;并在编译完后自动打开VS 转换前要备份 转换失败的原因 电脑上必须安装了.Net6.0&#xff0c;其他版本高了低了…

挖矿------获取以太坊测试币

文章目录 挖矿------获取以太坊测试币通过水龙头获取以太坊测试币了解Sepolia是什么&#xff1f;水龙头&#xff08;Faucet&#xff09;是什么&#xff1f;Gitcoin Passport是什么&#xff1f; 操作1.MetaMask钱包2.将MetaMask切换到Sepolia测试网络3.用MetaMask连接Gitcoin Pa…

玩转物联网-4G模块如何快速将数据上传到巴法云(TCP篇)

目录 1 前言 2 环境搭建 2.1 硬件准备 2.2 软件准备 2.3 硬件连接 2.4 检查驱动 3 巴法云平台设备创建 3.1 创建账号 3.2 进入巴法云 3.3 获取联网参数 4 连接巴法云 4.1 打开配置工具读取基本信息 4.2 设置连接参数进行数据交互 4.2.1 建立TCP连接 4.2.2 订阅主题 4.2.3 发布信…

Vue3 在组件中判断事件是否注册

效果 用途 我想用是否注册事件&#xff0c;来控制组件中图标的显示与隐藏 实现 通过组件中判断是否注册了相应的函数&#xff0c;来判断 const checkEvent () > {const instance getCurrentInstance();console.log(instance?.vnode?.props:>, instance?.vnode?…

ssh连接解析时间过长如何解决

[rootkvm ~]# vim /etc/ssh/sshd_config #修改配置 [rootkvm ~]# systemctl restart sshd #重启服务

【Linux】——进程状态僵尸进程孤儿进程

目录 前言 基本进程状态 运行状态 阻塞状态 挂起状态 Linux下的进程状态 僵尸进程 孤儿进程 结语 前言 进程的状态反映了它在执行过程中的不同阶段&#xff0c;例如创建、就绪、运行、阻塞和终止等。这些状态之间的转换由操作系统的调度算法和进程的行为共同决定。通…

信创系统极速文件查找:locate 命令详解

原文链接&#xff1a;信创系统极速文件查找&#xff1a;locate 命令详解 Hello&#xff0c;大家好啊&#xff01;今天给大家带来一篇信创终端操作系统上 locate 命令详解的文章。在 Linux 及信创终端操作系统&#xff08;如 统信 UOS、麒麟 KOS&#xff09;中&#xff0c;查找…

鸿蒙数据持久化之首选项

场景介绍 用户首选项为应用提供Key-Value键值型的数据处理能力&#xff0c;支持应用持久化轻量级数据&#xff0c;并对其修改和查询。当用户希望有一个全局唯一存储的地方&#xff0c;可以采用用户首选项来进行存储。Preferences会将该数据缓存在内存中&#xff0c;当用户读取…

PyTorch分布式训练中各节点如何通信

深度学习 文章目录 深度学习前言pytorch如何初始化分布式训练怎么知道要使用哪几台机器进行训练的如何根据标识进行初始化&#xff08;init_method&#xff09;如何获取进程的唯一标识rank如何实现数据如何分发 前言 同学们在处理分布式训练时经常会遇到以下几个疑问&#xff…

[数据结构]排序之 归并排序(有详细的递归图解)

一、非递归 基本思想&#xff1a; 归并排序&#xff08; MERGE-SORT &#xff09;是建立在归并操作上的一种有效的排序算法 , 该算法是采用分治法&#xff08; Divide andConquer&#xff09;的一个非常典型的应用。将已有序的子序列合并&#xff0c;得到完全有序的序列&#x…

在本地跑通spark环境

官网下载spark 下载spark 解压就好 本地配置环境变量 配置环境变量&#xff08;系统环境变量&#xff09; 新增 SPARK_HOME 变量名&#xff1a;SPARK_HOME 变量值&#xff1a;F:\class\spark\Spark_env\spark-3.4.4-bin-hadoop3 配置 PATH&#xff0c;新增如下&#xff1a…