文章目录

  • 效果图
  • 使用WindowManager实现
  • 分析
  • 问题
  • 参考

如果想实现一个在桌面显示的悬浮窗,用DialogPopupWindowToast等已经不能实现了,他们基本都是在Activity之上显示的,如果想实现在桌面显示的悬浮窗效果,需要用到WindowManager来实现了。

效果图

使用WindowManager实现

  • 添加一个悬浮窗:
        sys_view = new SmallWindowView(mContext);sys_view.setText("50%");sys_view.setOnTouchListener(this);windowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);int screenWidth = 0, screenHeight = 0;if (windowManager != null) {//获取屏幕的宽和高Point point = new Point();windowManager.getDefaultDisplay().getSize(point);screenWidth = point.x;screenHeight = point.y;layoutParams = new WindowManager.LayoutParams();
//            layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
//            layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;layoutParams.width = 200;layoutParams.height = 200;//设置typeif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {//26及以上必须使用TYPE_APPLICATION_OVERLAY   @deprecated TYPE_PHONElayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;} else {layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;}//设置flagslayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;layoutParams.gravity = Gravity.START | Gravity.TOP;//背景设置成透明layoutParams.format = PixelFormat.TRANSPARENT;layoutParams.x = screenWidth;layoutParams.y = screenHeight / 2;//将View添加到屏幕上windowManager.addView(sys_view, layoutParams);}
  • 更新悬浮窗位置:
windowManager.updateViewLayout(sys_view, layoutParams);
  • 关闭悬浮窗:
windowManager.removeView(sys_view);

通过上面的代码就可以实现一个桌面悬浮窗功能了。

注意:在6.0以上,需要在Manifest.xml中声明
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />权限并且在开启悬浮窗时动态判断权限,如果没有此权限需要跳到设置页面去设置,看下官方文档的说明:

分析

1、添加悬浮窗:
通过Context.getSystemService(Context.WINDOW_SERVICE)获得一个WindowManager以下简称VM), VM是外界访问Window的入口,ActivityDialogToast等其视图都是依附在Window之上的,WindowView的直接管理者,VM继承自ViewManager,其添加、刷新、删除方法也是来自ViewManager:

public interface ViewManager
{   public void addView(View view, ViewGroup.LayoutParams params);public void updateViewLayout(View view, ViewGroup.LayoutParams params);public void removeView(View view);
}

VM有一个静态内部类WindowManager.LayoutParamsWindow的各个属性在这个内部类中设置:

  • LayoutParams.TYPE
    如果TargetSdkVersion<26 ,那么可以直接使用LayoutParams.TYPE_PHONE或者LayoutParams.TYPE_SYSTEM_ALERT,在TargetSdkVersion>=26时,TYPE_PHONETYPE_SYSTEM_ALERT都已经废弃了,需要使用TYPE_APPLICATION_OVERLAY来标识TYPE
  • LayoutParams.FLAGS
    FLAGS表示Window的属性,通过FLAGS可以控制Window的显示特性,常用的几个特性:
    LayoutParams.FLAG_NOT_TOUCH_MODAL : 使用了此标识,可以将点击事件传递到悬浮窗以外的区域,反之其他区域的Window将接收不到事件。
    LayoutParams.FLAG_NOT_FOCUSABLE : 表示悬浮窗Window不需要获取焦点,也不需要获取各种输入事件,事件会直接传递给下层的具有焦点的Window
    LayoutParams.FLAG_SHOW_WHEN_LOCKED : 此模式可以让Window显示在锁屏的界面上
  • LayoutParams.FORMAT
    悬浮窗Window的背景格式,一般设置成PixelFormat.TRANSPARENT透明即可
  • LayoutParams.X & LayoutParams.Y
    悬浮窗Window在屏幕上的坐标值,可以根据X&Y的值来刷新Window在屏幕上的位置
  • LayoutParams.Width & LayoutParams.Height
    悬浮窗Window的宽度和高度

2、更新悬浮窗位置:
ViewOnTouchEvent中或OnTouch中更新layoutParams.xlayoutParams.y的值并通过windowManager.updateViewLayout()重新设置悬浮窗Window在屏幕中的位置,如下:

    @Overridepublic boolean onTouch(View v, MotionEvent event) {int mInScreenX = (int) event.getRawX();int mInScreenY = (int) event.getRawY();switch (event.getAction()) {case MotionEvent.ACTION_DOWN:mLastX = (int) event.getRawX();mLastY = (int) event.getRawY();break;case MotionEvent.ACTION_MOVE:layoutParams.x += mInScreenX - mLastX;layoutParams.y += mInScreenY - mLastY;mLastX = mInScreenX;mLastY = mInScreenY;windowManager.updateViewLayout(sys_view, layoutParams);break;case MotionEvent.ACTION_UP:break;}return true;}

3、删除悬浮窗:
删除比较简单,直接调用windowManager.removeView(view)viewWindow中删除即可。

问题

6.0以上使用时,需要动态申请该悬浮窗权限,如下:

//判断有没有悬浮窗权限,没有去申请
if(!Settings.canDrawOverlays(context)){Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,Uri.parse("package:" + context.getPackageName()));context.startActivityForResult(intent, REQUEST_CODE);
}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {switch (requestCode) {case REQUEST_CODE:if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return;if (!WindowUtil.canOverDraw(this)) {toast("悬浮窗权限未开启,请在设置中手动打开");return;}WindowController.getInstance().showThumbWindow();break;}}

通过Settings.canDrawOverlays(context)判断是否有悬浮窗权限,如果没有,跳转到设置页面去设置,并在onActivityResult ()中得到申请结果,看似很完美,但在实际测试中,发现在8.0以上的手机上有问题,即使在设置中同意了权限,8.0的手机Settings.canDrawOverlays(context)总是返回false,不过在关闭页面重新调用此方法时,又返回的true,感觉是有一定的延迟,google了一下,发现别人同样遇到了这个问题,貌似已经给google提交了bug单,可以看此博客:
http://paskov.vmsoft-bg.com/settings-candrawoverlays-allays-returns-false-on-android-o/ ,不过博客中的解决方法用我的8.0手机(HUAWEI MATE10)依然不起作用,暂时还没深入研究,有解决此问题的还希望不吝赐教。

以上例子的源码地址:https://github.com/crazyqiang

参考

【1】https://developer.android.com/reference/android/Manifest.permission#SYSTEM_ALERT_WINDOW

Android WindowManger实现桌面悬浮窗相关推荐

  1. Android桌面悬浮窗进阶,QQ手机管家小火箭效果实现

    这次我们将代码的重点放在火箭升空的效果上,因此简单起见,就直接在模仿360手机卫士悬浮窗的那份代码的基础上继续开发了,如果你还没有看过那篇文章的话,建议先去阅读 Android桌面悬浮窗效果实现,仿3 ...

  2. Android仿腾讯手机管家实现桌面悬浮窗小火箭发射的动画效果

    功能分析:  1.小火箭游离在activity之外,不依附于任何activity,不管activity是否开启,不影响小火箭的代码逻辑,所以小火箭的代码逻辑是要写在服务中:  2.小火箭挂载在手机窗体 ...

  3. (一)android 桌面悬浮窗 录屏源码放送

    看到几个网友留言需要源码参考,需要的可以拿走: 这里先提供几个工具类: 1.录屏工具类ScreenUtil.java package com.android.systemui.util;import ...

  4. android自动悬浮窗代码,Android_Android实现桌面悬浮窗、蒙板效果实例代码,现在很多安全类的软件,比如3 - phpStudy...

    Android实现桌面悬浮窗.蒙板效果实例代码 现在很多安全类的软件,比如360手机助手,百度手机助手等等,都有一个悬浮窗,可以飘浮在桌面上,方便用户使用一些常用的操作. 今天这篇文章,就是介绍如何实 ...

  5. Android桌面悬浮窗效果实现,仿360手机卫士悬浮窗效果

    转载自:http://blog.csdn.net/guolin_blog/article/details/8689140 大家好,今天给大家带来一个仿360手机卫士悬浮窗效果的教程,在开始之前请允许我 ...

  6. android 桌面悬浮窗 录屏时间控制显示效果

    悬浮窗效果如上图所示: 很简单的一个布局直接上代码 悬浮窗是在service中拉起可以根据个人需要修改 代码: (一)android 桌面悬浮窗 录屏源码放送 (二)android 桌面悬浮窗 录屏源 ...

  7. Java安卓如何添加悬浮窗_Android桌面悬浮窗效果实现

    360手机卫士我相信大家都知道,好多人手机上都会装这一款软件,那么我们对它的一个桌面悬浮窗效果想必都不会陌生.请看下图: 首先是一个小的悬浮窗显示的是当前使用了百分之多少的内存,点击一下小悬浮窗,就会 ...

  8. Android 实现视频的悬浮窗

    Android 实现视频的悬浮窗 如微信视频或者斗鱼直播一样,在应用切换到后台后,手机桌面还可以显示一个可以移动的小窗口,播放正在播放的内容.利用的就是android里面的WindowManager, ...

  9. 【Android】利用WindowsManager悬浮窗播放本地视频以及下载线上视频保存在本地

    基于目前又重新拾起了分屏的项目需求,对之前研究的分屏播放视频做了更深入的研究.在之前的基础上做了改进和用户优化上的处理,实现了原生的VideoView加载本地视频.并使用FileDownLoader下 ...

最新文章

  1. 基于蔡氏混沌电路进行非线性共振探究
  2. linux常用命令,知识在于总结
  3. XSS 注入漏洞处理
  4. linux 看不到mysql_linux的mysql下看不到mysql上的其他数据库只能看见 information_schema这一个数据库...
  5. android 捕捉home键
  6. phpstudy下载及简单使用教程
  7. dc dc变换器的建模及matlab仿真,巧用Matlab仿真DC—DC变换器
  8. 未来教育计算机二级答案,未来教育计算机二级操作题答案.docx
  9. 对与连连看求解算法的研究
  10. 大学英语(第三册)复习(原文及全文翻译)——Unit 7 - The Shelter(防空洞)
  11. 网易云音乐评论墙php源码,网易云音乐热评墙那些令人感慨的句子,哪一句打动了你?...
  12. 2021-08-14 WPF控件专题 ContextMenu 控件详解
  13. linux创建后门账户,Linux后门
  14. java 下载微信图片_java 微信服务器下载图片到自己服务器
  15. stm32 死区 刹车 pwm
  16. oracle强制拉库跳过recovery,学习笔记:Oracle坏块 数据库recover恢复时遇到坏块的解决思路案例...
  17. 通过SparkFun制作自己的Fritzing零件
  18. UiPath中文教程
  19. TMS320F28335DSP简介及最小系统设计
  20. 多ip服务器数据怎么备份?

热门文章

  1. PDF怎么转换为CAD?这里有个好用的方法
  2. RISC-V SIG 新进展:Chromium 等多个桌面软件登录欧拉开源操作系统
  3. 低粉高播放!30万粉竟打造900万播放的B站恰饭
  4. 基础篇:9)装配流程图
  5. 深入学习 jQuery 选择器系列第三篇——过滤选择器之索引选择器 - 小火柴的蓝色理想 - 博客园...
  6. ubuntu系统利用路由器上网设置
  7. 简易区块链C语言实现
  8. 苹果开发者账号中,测试机器列表达到100台上限,如何删除一些设备、添加新设备?
  9. 分布式session详解
  10. 软考每年成绩几月公布 软考考试历年成绩查询时间