代码比较简单。不会有详细的讲解,这个功能我之前是用来做实时音视频小窗口悬浮的,所以说最外层是FrameLayout,可以根据自己的需求变成图片,或者功能界面,都可以的。

准备工作:AndroidManifest添加权限

<uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /><--! 说明一下,第一个权限是8.0之后悬浮窗窗口类型设置需要,第二个权限假如不加的话,我oppo手机跳转悬浮窗设置时,找不到这个app -->

以及需要了解一些小知识:触摸事件中:getX getY是相对于当前View里的坐标; getRawX getRawY是相对于整个屏幕的坐标

大致思路:获取View添加至窗口 触摸View的时候,根据触摸位置更新悬浮窗口位置,点击后,把这个View从窗口移除

上一下完成的图,用UC视频转gif转不了很长:

代码都有注释,直接看代码:

package com.zh.pullrefresh;import android.content.Context;
import android.graphics.PixelFormat;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.ImageView;import androidx.annotation.NonNull;public class SmallWindowsView extends FrameLayout {private int mSlop;//触发移动事件的最小距离private float downX;//手指放下去的x坐标private float downY;//手指放下去的Y坐标/*** 下面四个数据都为像素*/private int screenWidth;//屏幕宽度private int screenHeight;//屏幕高度private int viewWidth;//小窗的宽度private int viewHeight;//小窗的高度private WindowManager wm;//窗口管理器,用来把view添加进窗口层private WindowManager.LayoutParams wmParams;public SmallWindowsView(@NonNull Context context) {super(context);init();}private void init() {ViewConfiguration vc = ViewConfiguration.get(getContext());mSlop = vc.getScaledTouchSlop();screenWidth = getContext().getResources().getDisplayMetrics().widthPixels;screenHeight = getContext().getResources().getDisplayMetrics().heightPixels;viewWidth = dp2px(getContext(), 130);viewHeight = dp2px(getContext(), 130);//可以根据你的实际情况在这个FrameLayout里添加界面控件之类的,// 我之前是用的实时音视频,把相关业务代码去掉了,直接放一个图标// 实际上就是拿到一个View从WindowManager给addView进去ImageView imageView = new ImageView(getContext());imageView.setImageResource(R.mipmap.ic_launcher);LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT);addView(imageView, params);}//dp转pxpublic int dp2px(Context context, int dp) {return (int) (getDensity(context) * dp + 0.5);}public float getDensity(Context context) {return context.getResources().getDisplayMetrics().density;}public void show() {wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);wmParams = new WindowManager.LayoutParams(viewWidth, viewHeight,WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,//8.0以上需要用这个权限WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,PixelFormat.TRANSLUCENT);wmParams.gravity = Gravity.NO_GRAVITY;wmParams.x = screenWidth/2 - viewWidth/2;wmParams.y = screenHeight/2 - viewHeight/2;wm.addView(this, wmParams);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);//本来想在这边直接设置宽高,但是有问题
//        setMeasuredDimension(QMUIDisplayHelper.dp2px(getContext(), 130), QMUIDisplayHelper.dp2px(getContext(), 130));}//拦截触摸事件自己消费@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {return true;}private long downTime;private float lastMoveX;private float lastMoveY;//消费触摸事件@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:downX = event.getRawX();downY = event.getRawY();lastMoveX = downX;lastMoveY = downY;downTime = System.currentTimeMillis();break;case MotionEvent.ACTION_MOVE:float moveX = event.getRawX();float moveY = event.getRawY();//就两个坐标算他们距离要大于触发移动事件的最小距离//这里也可以减去lastMoveX lastMoveY 但是移动会有卡顿感 因此这里使用的还是downX downYif (Math.pow(Math.abs(moveX - downX), 2) + Math.pow(Math.abs(moveY - downY), 2) > Math.pow(mSlop, 2)) {updateViewPosition(moveX - lastMoveX, moveY - lastMoveY);lastMoveX = moveX;lastMoveY = moveY;}break;case MotionEvent.ACTION_UP:float upX = event.getRawX();float upY = event.getRawY();long upTime = System.currentTimeMillis();long time = upTime - downTime;//点击事件实现 点击小窗口消失//这里加了时间判断,是因为假如移动到原来的地方,也会触发成点击事件if (Math.pow(Math.abs(upX - downX), 2) + Math.pow(Math.abs(upY - downY), 2) < Math.pow(mSlop, 2) && time < 1000) {showRtcVideo();} else {}break;}return true;}private void showRtcVideo() {dismiss();
//        Toast.makeText(getContext(), "aaaaaaaaa", Toast.LENGTH_SHORT).show();}public void dismiss() {wm.removeView(this);}private void updateViewPosition(float moveX, float moveY) {wmParams.gravity = Gravity.NO_GRAVITY;//更新浮动窗口位置参数//        Log.d("moveX, moveY", moveX + "--" + moveY);wmParams.x = (int) (wmParams.x + moveX);wmParams.y = (int) (wmParams.y + moveY);//        刷新显示wm.updateViewLayout(this, wmParams);}
}

那么使用上需要注意一点,我new这个控件的时候,使用的context是application层级的,因为多个activity,悬浮窗窗口的生命周期明显是属于整个程序的,而不是属于某个activity,当然你假如做处理的话,也可以这么做:

@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);final SmallWindowsView smallWindowsView = new SmallWindowsView(getApplicationContext());Button btShowWindow = findViewById(R.id.bt_show_window);btShowWindow.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (Build.VERSION.SDK_INT >= 23) {if (!(Settings.canDrawOverlays(MainActivity.this))) {Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);startActivity(intent);return;}} else {if (!EasyPermissions.hasPermissions(MainActivity.this, Manifest.permission.SYSTEM_ALERT_WINDOW)) {EasyPermissions.requestPermissions(MainActivity.this, "需要权限用以展示悬浮窗",2048, Manifest.permission.SYSTEM_ALERT_WINDOW);return;}}smallWindowsView.show();}});}

注意权限的动态获取

Android:触摸移动的悬浮窗口相关推荐

  1. android实现 桌面移动悬浮窗口实现

    现在很多应用都有这样的功能,比如360等安全卫士,手机管家之内的应用. 效果图: 一.实现原理及移动思路 调用WindowManager,并设置WindowManager.LayoutParams的相 ...

  2. android多个悬浮窗口的实现,android实现桌面移动悬浮窗口

    现在很多应用都有这样的功能,比如360等安全卫士,手机管家之内的应用. 效果图: 一.实现原理及移动思路 调用WindowManager,并设置WindowManager.LayoutParams的相 ...

  3. android WindowManager 应用内部悬浮窗口总结

    很多地方用到悬浮窗口,但是android现在做了很多限制,禁止悬浮窗口的滥用,尤其是系统权限的窗口基本不予支持,以下是介绍应用内部悬浮窗口不需要任何系统权限的 1   显示一个悬浮窗 // wm = ...

  4. android可以有一个悬浮窗口在进入屏保状态显示,点击进入应用,Android如何实现锁屏状态下弹窗...

    前言 想在锁屏上面实现弹窗,第一个想法就是利用 WindowManager设置 Window的 Flag,通过设置 Flag的显示优先级来让窗口显示在锁屏的上面. 接下来就是试验可能相关的 Windo ...

  5. 细数Android 7.0“牛轧糖”的五大缺陷:不支持悬浮窗口

    导语:当前,Android 7.0 Nougat(牛轧糖)已经开始被缓慢部署至全球各地的Android设备中.按照惯例,仍然是Nexus设备首先获得谷歌最新的移动操作系统,其他的智能手机则还需要等待一 ...

  6. Android 悬浮窗口

    Android 悬浮窗口 一.创建悬浮窗口步骤     1.实现一个ViewGroup类,作为悬浮窗口的界面类,以便在里面重写onInterceptTouchEvent和onTouchEvent方法, ...

  7. Android WindowManager和WindowManager.LayoutParams的使用以及实现悬浮窗口的方法

    1.理清概念 我们使用过Dialog和PopupWindow,还有Toast,它们都显示在Activity之上.那么我们首先需要理解的是android中是如何去绘制这些UI的呢?这里我只讲我所理解的, ...

  8. android 添加随意拖动的桌面悬浮窗口,android 添加随意拖动的桌面悬浮窗口

    用过新版本android 360手机助手都人都对 360中只在桌面显示一个小小悬浮窗口羡慕不已吧? 其实实现这种功能,主要有两步: 1.判断当前显示的是为桌面.这个内容我在前面的帖子里面已经有过介绍, ...

  9. android 全局 窗口,学习笔记:WindowManager显示Android全局悬浮窗口

    我用Android手机装了个电商软件,抢购用.自己手机的状态栏不能显示秒级别的时间,只能精确到分钟.为了能准确的把握抢购时间,自己边学习边开发了一个时间显示悬浮窗. WindowManager 参考文 ...

最新文章

  1. JSFL元件类型判断 转载于 https://blog.csdn.net/linking530/article/details/8364600
  2. 如何检查对象的类型[iOS/Android/Windows Phone]
  3. How can I exclude directories from grep -R?
  4. 根据屏幕分辨率获取css,根据判断浏览器类型屏幕分辨率自动调用不同CSS的代码...
  5. 关于string转int、float、double常用方法
  6. Windbg命令学习6(!runaway和~)
  7. Android在线更新安装包,Android在线更新下载方案
  8. IOS自定义UITableViewCell的高亮背景色
  9. 使用weui滚动加载结合php实现分类页数据列表
  10. 【系列三之CentOS系列】Shell编程入门(3)
  11. H3C无线 AC旁挂式部署无线开局(WEB版)
  12. 【多线程与高并发】这可能是最全的多线程面试题了
  13. 直方图python_python实现直方图的应用
  14. python已停止工作请关闭该程序_解决PyCharm的Python.exe已经停止工作的问题
  15. 怎样更改itunes备份位置_正确修改itunes备份文件路径方法
  16. 查询QQ会员账号信息API接口
  17. ElasticSearch基础教程
  18. 自动化系2023挑战杯预审相关资料
  19. 利用Python进行数据分析之超市零售分析
  20. android——沙漏计时器

热门文章

  1. inurl+:php?id,实操:SQL注入国外xx网站
  2. python爬虫实战:猫眼电影我不是药神评论
  3. 这个日期格式是什么? 2011-08-12T20:17:46.384Z
  4. python--转换wrf输出的风场数据为网页可视化的json格式
  5. JDBC数据库连接测试工具
  6. oc-分类(catgory)的概念及使用
  7. 实现永久关闭445服务
  8. Windows7UltimateSP1x64安装及一些设置
  9. MFC 多个RadioButton设为一组 vs2013
  10. JavaWeb_基础知识