当前位置: 首页 > news >正文

安卓悬浮窗口,  丝滑双指缩放视频窗口

最重要的事情说前面: demo源码:

https://github.com/5800LDW/ProjectFloatingWindow

前言:

1.跨应用的浮动窗口在网上很多资料, 就不细说了。

2.双指缩放View 也很多资料, 可参考:

https://blog.csdn.net/zxq614/article/details/88873729

正文

下面进入正题, 如何把上述结合起来, 下面在前言2 的ZoomView 上进行改造。

下面帖一下原始ZoomView的代码:

      public class ZoomView extends RelativeLayout {// 属性变量private float translationX; // 移动Xprivate float translationY; // 移动Yprivate float scale = 1; // 伸缩比例private float rotation; // 旋转角度// 移动过程中临时变量private float actionX;private float actionY;private float spacing;private float degree;private int moveType; // 0=未选择,1=拖动,2=缩放public ZoomView(Context context) {this(context, null);}public ZoomView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public ZoomView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);setClickable(true);}@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {getParent().requestDisallowInterceptTouchEvent(true);return super.onInterceptTouchEvent(ev);}@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction() & MotionEvent.ACTION_MASK) {case MotionEvent.ACTION_DOWN:moveType = 1;actionX = event.getRawX();actionY = event.getRawY();break;case MotionEvent.ACTION_POINTER_DOWN:moveType = 2;spacing = getSpacing(event);degree = getDegree(event);break;case MotionEvent.ACTION_MOVE:if (moveType == 1) {translationX = translationX + event.getRawX() - actionX;translationY = translationY + event.getRawY() - actionY;setTranslationX(translationX);setTranslationY(translationY);actionX = event.getRawX();actionY = event.getRawY();} else if (moveType == 2) {scale = scale * getSpacing(event) / spacing;setScaleX(scale);setScaleY(scale);rotation = rotation + getDegree(event) - degree;if (rotation > 360) {rotation = rotation - 360;}if (rotation < -360) {rotation = rotation + 360;}setRotation(rotation);}break;case MotionEvent.ACTION_UP:case MotionEvent.ACTION_POINTER_UP:moveType = 0;}return super.onTouchEvent(event);}// 触碰两点间距离private float getSpacing(MotionEvent event) {//通过三角函数得到两点间的距离float x = event.getX(0) - event.getX(1);float y = event.getY(0) - event.getY(1);return (float) Math.sqrt(x * x + y * y);}// 取旋转角度private float getDegree(MotionEvent event) {//得到两个手指间的旋转角度double delta_x = event.getX(0) - event.getX(1);double delta_y = event.getY(0) - event.getY(1);double radians = Math.atan2(delta_y, delta_x);return (float) Math.toDegrees(radians);}}

具体思路

下面具体讲思路, 具体代码在文首:

1.首先

我们不需要旋转, 所以注释掉

//setRotation(rotation);

2.我们要解决平移问题。

上文的setTranslationX是相对于父布局来实现的, 但是我们悬浮窗不会充满全屏, 而且后面我们要缩小/放大, 父布局的大小是要变化的, 所以上文的setTranslationX和translationY都要注释掉。

悬浮窗移动是通过WindowManager的updateViewLayout方法来实现的。所以我们加入一个内部接口, 提供给WindowManager进行调用updateViewLayout, 修改后的代码如下:

ZoomView的修改如下:

          case MotionEvent.ACTION_MOVE:if (moveType == 1) {translationX = translationX + event.getRawX() - actionX;;translationY = translationY + event.getRawY() - actionY;//父view先变换位置就行了;if (translationListener != null) {translationListener.translation(translationX, translationY);}//setTranslationX(translationX);//setTranslationY(translationY);actionX = event.getRawX();actionY = event.getRawY();} 

接口TranslationListener的translation方法的具体实现:

    @Overridepublic void translation(float actionX, float actionY) {wmParams.x = (int) actionX;wmParams.y = (int) actionY;wm.updateViewLayout(view, wmParams);}

3.解决缩放的问题。

ZoomView的setScaleX(scale); setScaleY(scale); 是需要保留的, 同时, 父view也要进行缩放/放大。

所以我们同样引入一个接口方法提供给Params进行修改 width 和 height ,然后调用WindowManager的updateViewLayout。

ZoomView的修改如下:

 else if (moveType == 2) {scale = scale * getSpacing(event) / spacing;//核心是先改变父类的位置, 然后再缩小子类if (translationListener != null) {translationListener.scale(scale);}setScaleX(scale);setScaleY(scale);

接口TranslationListener的scale方法的具体实现:

...
@Override
public void scale(float scale) {//因为我把悬浮窗默认的宽是300, 所以这里就直接拿300作为宽高的初始值, 后面的缩放、放大都是在这个初始值上进行float normalPx = dp2px(300f);Log.e("TAG ", " normalPx = " + normalPx);wmParams.width = (int) (normalPx * scale);wmParams.height = (int) (normalPx * scale);wm.updateViewLayout(view, wmParams);}
...

到这一步的时候, 能平移也能缩小/放大了, 但是, 会有个问题, 就是ZoomView不会在父view居中了, 经测试, 使用ConstraintLayout包裹ZoomView, 并设置ZoomView居中, 在缩放ZoomView后能居中在父布局中显示。这里可能跟约束布局的实现有关, 有了解的同学可以说一下...

4.视频播放。

下面我们就放入视频播放的view被ZoomView包裹 , 看看视频播放是否卡顿。

源码里面使用的是GSYVideoPlayer的播放控件。 图就不截图了, 具体看源码就OK。

5.视频播放后引入的问题。

视频播放的控件也是会获取触控事件的, 会导致ZoomView的onTouchEvent不生效, 所以这里涉及到事件分发的问题。但是, ZoomView处理View的位置、大小变化, 本身不跟播放的View的触摸事件有冲突的, 所以我们把ZoomView的onTouchEvent的变化位置、大小的代码改到onInterceptTouchEvent里面实现即可。

题外话: demo是基础实现, 具体很多细节, 例如设定最大的放大数值, 设定最小的缩小数值等等, 还得需要进行处理的。

感谢并推荐阅读:

https://blog.csdn.net/zxq614/article/details/88873729

https://github.com/CarGuo/GSYVideoPlayer

相关文章:

安卓悬浮窗口,  丝滑双指缩放视频窗口

最重要的事情说前面: demo源码:https://github.com/5800LDW/ProjectFloatingWindow前言:1.跨应用的浮动窗口在网上很多资料, 就不细说了。2.双指缩放View 也很多资料, 可参考:https://blog.csdn.net/zxq614/article/details/88873729正文下面进入正题, 如何把上述结合起来, 下面…...

300左右哪款蓝牙耳机适合学生用?四款便宜质量好的蓝牙耳机推荐

近年来&#xff0c;随着蓝牙耳机的发展&#xff0c;不管是音质、外观、佩戴还是降噪都有了很大的提升。但是我们在入手蓝牙耳机时&#xff0c;最好还是根据预算和需求入手。在此&#xff0c;我来给预算在三百内的朋友推荐几款便宜质量好的蓝牙耳机&#xff0c;可以当个参考。 …...

桥梁设计模式

介绍 Java桥梁模式(也称桥接模式)(Bridge Pattern)是一种设计模式,它将抽象和实现分离,使它们可以独立地变化.它通过一个大类或者一系列紧密关联的类拆分成两个独立的层次结构来实现这种分离,其中一个层次结构包含抽象类或接口,另一个层次结构包含实现类.桥梁模式使得抽象类和…...

【华为OD机试 2023最新 】 新员工座位(C++)

文章目录 题目描述输入描述输出描述用例题目解析C++题目描述 工位由序列F1,F2…Fn组成,Fi值为0、1或2。其中0代表空置,1代表有人,2代表障碍物。 1、某一空位的友好度为左右连续老员工数之和, 2、为方便新员工学习求助,优先安排友好度高的空位, 给出工位序列,求所有空…...

蓝桥杯刷题第二十二天

第一题&#xff1a;受伤的皇后题目描述有一个 nn 的国际象棋棋盘&#xff08;n 行 n 列的方格图&#xff09;&#xff0c;请在棋盘中摆放 n 个受伤的国际象棋皇后&#xff0c;要求&#xff1a;任何两个皇后不在同一行。任何两个皇后不在同一列。如果两个皇后在同一条 45 度角的…...

CentOS从gcc 4.8.5 升级到gcc 8.3.1

gcc -v查看当前gcc版本。 sudo yum install centos-release-scl-rh安装centos-release-scl-rh。 sudo yum install devtoolset-8-build安装devtoolset-8-build。 显示“Complete!”表示安装成功。 sudo yum install devtoolset-8-gdb安装devtoolset-8-gdb。 显示“Comple…...

【人人都能读标准】12. 原始类型的编码形式

本文为《人人都能读标准》—— ECMAScript篇的第12篇。我在这个仓库中系统地介绍了标准的阅读规则以及使用方式&#xff0c;并深入剖析了标准对JavaScript核心原理的描述。 ECMAScript有7种原始类型&#xff0c;分别是Undefined、Null、Boolean、String、Number、BigInt、Symbo…...

VUE进行前后端交互

目录 一、 跨域 1. 什么是跨域&#xff1f; 2. 什么是本域&#xff1f; 3. 浏览器请求的三种报错 二、SpringBoot解决跨域问题其他前后端跨域请求解决方案 1. SpringBoot上直接添加CrossOrigin 2. 处理跨域请求的Configuration 3. 采用过滤器的方式 3.1 方式一 3.2 方式…...

ThingsBoard Gateway:物联网设备数据采集与集成的强大解决方案

文章目录ThingsBoard Gateway&#xff1a;物联网设备数据采集与集成的强大解决方案1\. ThingsBoard Gateway&#xff1a;概述2\. 主要特点与优势3\. 应用场景4\. 如何使用ThingsBoard Gateway&#xff1a;物联网设备数据采集与集成的强大解决方案 随着物联网&#xff08;IoT&a…...

什么是镜像/raid

镜像&#xff08;Mirroring&#xff09;是一种文件存储形式&#xff0c;是冗余的一种类型&#xff0c;一个磁盘上的数据在另一个磁盘上存在一个完全相同的副本即为镜像。可以把许多文件做成一个镜像文件&#xff0c;与GHOST等程序放在一个盘里用GHOST等软件打开后&#xff0c;又…...

【Python】如何有效比较两个时间序列在图形上的相似度?

文章目录前言一、1.准备二、实操1.使用Matplotlib可视化比较两个时间序列2.计算两个时间序列的相关系数&#xff1a;3.使用Python实现动态时间规整算法&#xff08;DTW&#xff09;&#xff1a;总结前言 比较两个时间序列在图形上是否相似&#xff0c;可以通过以下方法&#x…...

JavaEE-常见的锁策略和synchronized的锁机制

目录常见的锁策略乐观锁和悲观锁轻量级锁和重量级锁自旋锁和挂起等待锁普通互斥锁和读写锁公平锁和非公平锁可重入锁和不可重入锁synchronized的锁机制synchronized特性锁升级/锁膨胀锁消除锁粗化常见的锁策略 乐观锁和悲观锁 乐观锁和悲观锁主要是看主要是锁竞争的激烈程度.…...

信息化,数字化,智能化是三种不同的概念吗?

前两年流行“信息化”&#xff0c;网上铺天盖地都是关于“信息化”的文章&#xff0c;这两年开始流行起“数字化”&#xff0c;于是铺天盖地都是“数字化”的文章。&#xff08;这一点从数字化和信息化这两个关键词热度趋势就可以看出来&#xff09;。 但点开那些文章仔细看看…...

【华为OD机试 2023最新 】 匿名信(C++ 100%)

题目描述 电视剧《分界线》里面有一个片段,男主为了向警察透露案件细节,且不暴露自己,于是将报刊上的字减下来,剪拼成匿名信。 现在又一名举报人,希望借鉴这种手段,使用英文报刊完成举报操作。 但为了增加文章的混淆度,只需满足每个单词中字母数量一致即可,不关注每个…...

硬件语言Verilog HDL牛客刷题day05 时序逻辑部分

1.VL29 信号发生器 1.题目&#xff1a; 题目描述&#xff1a; 请编写一个信号发生器模块&#xff0c;根据波形选择信号wave_choise发出相应的波形&#xff1a;wave_choice0时&#xff0c;发出方波信号&#xff1b;wave_choice1时&#xff0c;发出锯齿波信号&#xff1b;wave…...

Ajax 入门

前端技术&#xff1a;在浏览器中执行的程序都是前端技术。如 html、css、js 等 后端技术&#xff1a;在服务器中执行的长须&#xff0c;使用 Java 等语言开发的后端程序。servlet&#xff0c;jsp&#xff0c;jdbc&#xff0c;mysql&#xff0c;tomacat 等 全局刷新 使用表单…...

半导体器件基础06:发光二极管

说在开头&#xff1a;关于玻尔原子模型&#xff08;1&#xff09; 卢瑟福的模型面临着与经典电磁波理论的矛盾&#xff0c;按照经典电磁波理论&#xff0c;卢瑟福的原子不可能稳定存在超过1秒钟。玻尔面临着选择&#xff1a;要么放弃卢瑟福模型&#xff0c;要么放弃麦克斯韦伟…...

AutoCV第二课:Python基础

目录Python基础前言1.流程控制1.1 条件语句1.2 循环语句1.2.1 while循环语句1.2.2 for循环语句1.3 作业1.4 拓展-try except语法2.函数2.1 函数定义2.2 函数的参数2.2.1 位置参数2.2.2 命名参数2.2.3 默认参数2.2.4 可变参数2.2.5 参数展开2.3 递归函数2.3.1 递归函数定义2.3.2…...

LeetCode算法 打家劫舍 和 打家劫舍II C++

目录题目 打家劫舍参考答案题目 打家劫舍II参考答案题目 打家劫舍 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&#xff0c;如果两间相邻的房屋在同一晚上被小偷闯…...

蓝桥杯刷题冲刺 | 倒计时10天

作者&#xff1a;指针不指南吗 专栏&#xff1a;蓝桥杯倒计时冲刺 &#x1f43e;马上就要蓝桥杯了&#xff0c;最后的这几天尤为重要&#xff0c;不可懈怠哦&#x1f43e; 文章目录1.有边数限制的最短路2.九进制转十进制1.有边数限制的最短路 题目 链接&#xff1a; 853. 有边数…...

【JVM】面试题-有哪些垃圾回收器

【JVM】面试题-有哪些垃圾回收器 在JVM的内存管理中&#xff0c;垃圾收集算法是内存回收的核心逻辑与方法论&#xff0c;而垃圾收集器则是将这套方法论落地实现的具体工具。 不同的垃圾收集器针对JVM堆的不同分代&#xff08;新生代、老年代&#xff09;设计&#xff0c;具备不…...

应用间自动化网关:构建私有化、可编程的跨平台工作流中枢

1. 项目概述与核心价值最近在折腾一些跨平台、跨设备的自动化流程&#xff0c;发现一个痛点&#xff1a;不同应用、不同服务之间的数据流转&#xff0c;经常需要手动“搭桥”。比如&#xff0c;想把手机上的一个链接快速推送到电脑上处理&#xff0c;或者把某个文档从A服务同步…...

GPT-Image-2提示词工程实战:从原理到应用,解锁高质量AI图像生成

1. 项目概述&#xff1a;一份高质量的GPT-Image-2提示词工程指南如果你正在使用OpenAI的GPT-Image-2模型&#xff0c;并且厌倦了反复尝试却只能得到平庸、不符合预期的图片&#xff0c;那么你找对地方了。我最近深度研究并实践了Anil-matcha维护的“Awesome GPT-Image-2 API Pr…...

冻|结D球 2026

通过网盘分享的文件&#xff1a;冻&#xff5c;结D球 2026 链接: https://pan.baidu.com/s/1-bhxibfD69ahEoufeQFRRQ?pwdhygv 提取码: hygv...

SatGate-Proxy:开源反向代理与隧道工具部署与实战指南

1. 项目概述与核心价值最近在折腾一些需要跨地域、跨网络环境访问的应用时&#xff0c;遇到了一个老生常谈的痛点&#xff1a;如何稳定、高效地访问那些因为网络策略限制而无法直接触达的服务。这不仅仅是个人用户的需求&#xff0c;很多中小团队在部署混合云、进行远程办公或访…...

WP Pinch:通过MCP协议为WordPress站点集成AI助手管理能力

1. 项目概述&#xff1a;当你的WordPress站点“长出”AI的爪子 如果你和我一样&#xff0c;每天大部分时间都泡在Slack、Telegram或者WhatsApp里&#xff0c;和团队沟通、处理信息&#xff0c;那么你肯定也烦透了那种“这个内容不错&#xff0c;等我回到电脑前再发到网站上”的…...

Dify实战指南:从零构建大模型应用与智能体开发全流程

1. 项目概述&#xff1a;从零到一&#xff0c;构建你的大模型应用开发实战手册如果你对AI应用开发感兴趣&#xff0c;但又觉得从零开始搭建一个能用的智能体&#xff08;Agent&#xff09;或者知识库问答系统门槛太高&#xff0c;那么你很可能已经听说过Dify这个名字。作为一个…...

ksail:本地Kubernetes开发环境一键搭建与云原生实践

1. 项目概述&#xff1a;当Kubernetes遇上本地开发如果你是一名后端或云原生方向的开发者&#xff0c;大概率经历过这样的场景&#xff1a;为了调试一个微服务&#xff0c;你需要在本地启动一整套依赖——数据库、消息队列、缓存&#xff0c;可能还有另外两三个兄弟服务。你手忙…...

音频AI DSP:低功耗边缘智能的硬件架构与实现

1. 项目概述&#xff1a;当音频AI遇见边缘DSP几年前&#xff0c;如果有人告诉我&#xff0c;一个比指甲盖还小的芯片&#xff0c;能在不到1毫瓦的功耗下&#xff0c;持续监听环境声音、识别特定关键词&#xff0c;甚至能分辨出你是在嘈杂的餐厅还是在安静的办公室&#xff0c;我…...

从图文到视频:用 Python 打造公众号文章自动化转视频号的爆款流水线

摘要:本文详解一套完全基于开源工具(Python + edge-tts + ffmpeg)的自动化系统,可将任意微信公众号文章一键转换为横屏/竖屏视频,直接用于视频号分发。全程无需剪辑软件、无需出镜、无需复杂配置,5 分钟部署,1 条命令生成专业级视频。 🔥 为什么你需要这个? 在 AIGC…...