悬浮窗的另外一种使用

转自:http://blog.csdn.net/shinay/article/details/7783276

下面是创建悬浮窗的方法:

[java] view plain copy

  1. private boolean isAdded = false; // 是否已增加悬浮窗
  2. private static WindowManager wm;
  3. private static WindowManager.LayoutParams params;
  4. private Button btn_floatView;

[java] view plain copy

  1. /**
  2. * 创建悬浮窗
  3. */
  4. private void createFloatView() {
  5. btn_floatView = new Button(getApplicationContext());
  6. btn_floatView.setText("悬浮窗");
  7. wm = (WindowManager) getApplicationContext()
  8. .getSystemService(Context.WINDOW_SERVICE);
  9. params = new WindowManager.LayoutParams();
  10. // 设置window type
  11. params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
  12. /*
  13. * 如果设置为params.type = WindowManager.LayoutParams.TYPE_PHONE;
  14. * 那么优先级会降低一些, 即拉下通知栏不可见
  15. */
  16. params.format = PixelFormat.RGBA_8888; // 设置图片格式,效果为背景透明
  17. // 设置Window flag
  18. params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
  19. | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
  20. /*
  21. * 下面的flags属性的效果形同“锁定”。
  22. * 悬浮窗不可触摸,不接受任何事件,同时不影响后面的事件响应。
  23. wmParams.flags=LayoutParams.FLAG_NOT_TOUCH_MODAL
  24. | LayoutParams.FLAG_NOT_FOCUSABLE
  25. | LayoutParams.FLAG_NOT_TOUCHABLE;
  26. */
  27. // 设置悬浮窗的长得宽
  28. params.width = 100;
  29. params.height = 100;
  30. // 设置悬浮窗的Touch监听
  31. btn_floatView.setOnTouchListener(new OnTouchListener() {
  32. int lastX, lastY;
  33. int paramX, paramY;
  34. public boolean onTouch(View v, MotionEvent event) {
  35. switch(event.getAction()) {
  36. case MotionEvent.ACTION_DOWN:
  37. lastX = (int) event.getRawX();
  38. lastY = (int) event.getRawY();
  39. paramX = params.x;
  40. paramY = params.y;
  41. break;
  42. case MotionEvent.ACTION_MOVE:
  43. int dx = (int) event.getRawX() - lastX;
  44. int dy = (int) event.getRawY() - lastY;
  45. params.x = paramX + dx;
  46. params.y = paramY + dy;
  47. // 更新悬浮窗位置
  48. wm.updateViewLayout(btn_floatView, params);
  49. break;
  50. }
  51. return true;
  52. }
  53. });
  54. wm.addView(btn_floatView, params);
  55. isAdded = true;
  56. }

做完这步,基本上就可以在桌面显示一个悬浮窗并且可以自由拖动了。

如果想要控制它在桌面显示,而进入到别的应用程序时隐藏它的话,就需要用一个后台运行的Service来实现了。

首先需要先获取到手机上的桌面程序的包名(桌面程序指的是按下HOME键所列出的程序,如go桌面等):

[java] view plain copy

  1. /**
  2. * 获得属于桌面的应用的应用包名称
  3. * @return 返回包含所有包名的字符串列表
  4. */
  5. private List<String> getHomes() {
  6. List<String> names = new ArrayList<String>();
  7. PackageManager packageManager = this.getPackageManager();
  8. // 属性
  9. Intent intent = new Intent(Intent.ACTION_MAIN);
  10. intent.addCategory(Intent.CATEGORY_HOME);
  11. List<ResolveInfo> resolveInfo = packageManager.queryIntentActivities(intent,
  12. PackageManager.MATCH_DEFAULT_ONLY);
  13. for(ResolveInfo ri : resolveInfo) {
  14. names.add(ri.activityInfo.packageName);
  15. }
  16. return names;
  17. }

接着是判断当前运行的Activity是否为桌面应用程序,这里需要用到ActivityManager:

[java] view plain copy

  1. /**
  2. * 判断当前界面是否是桌面
  3. */
  4. public boolean isHome(){
  5. if(mActivityManager == null) {
  6. mActivityManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
  7. }
  8. List<RunningTaskInfo> rti = mActivityManager.getRunningTasks(1);
  9. return homeList.contains(rti.get(0).topActivity.getPackageName());
  10. }

有了上面两个方法,就可以实现这个功能了。只不过我们需要定时去判断,例如可以用一个Handler每一秒去检查一次:

[java] view plain copy

  1. private Handler mHandler = new Handler() {
  2. @Override
  3. public void handleMessage(Message msg) {
  4. switch(msg.what) {
  5. case HANDLE_CHECK_ACTIVITY:
  6. if(isHome()) {
  7. if(!isAdded) {
  8. wm.addView(btn_floatView, params);
  9. isAdded = true;
  10. }
  11. } else {
  12. if(isAdded) {
  13. wm.removeView(btn_floatView);
  14. isAdded = false;
  15. }
  16. }
  17. mHandler.sendEmptyMessageDelayed(HANDLE_CHECK_ACTIVITY, 1000);
  18. break;
  19. }
  20. }
  21. };

在我的Demo中,悬浮窗都是通过Service来控制的,那么我的启动与隐藏就都扔给Service处理就OK。

[java] view plain copy

  1. public void onClick(View v) {
  2. switch(v.getId()) {
  3. case R.id.btn_show:
  4. Intent show = new Intent(this, FloatingWindowService.class);
  5. show.putExtra(FloatingWindowService.OPERATION, FloatingWindowService.OPERATION_SHOW);
  6. startService(show);
  7. break;
  8. case R.id.btn_hide:
  9. Intent hide = new Intent(this, FloatingWindowService.class);
  10. hide.putExtra(FloatingWindowService.OPERATION, FloatingWindowService.OPERATION_HIDE);
  11. startService(hide);
  12. break;
  13. }
  14. }

在Service里的onStart方法中,只需要根据传过来的操作参数,对handler检查进行操作即可。

[java] view plain copy

  1. @Override
  2. public void onStart(Intent intent, int startId) {
  3. super.onStart(intent, startId);
  4. int operation = intent.getIntExtra(OPERATION, OPERATION_SHOW);
  5. switch(operation) {
  6. case OPERATION_SHOW:
  7. mHandler.removeMessages(HANDLE_CHECK_ACTIVITY);
  8. mHandler.sendEmptyMessage(HANDLE_CHECK_ACTIVITY);
  9. break;
  10. case OPERATION_HIDE:
  11. mHandler.removeMessages(HANDLE_CHECK_ACTIVITY);
  12. break;
  13. }
  14. }

另外:需要增加以下权限!!

[html] view plain copy

  1. <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
  2. <uses-permission android:name="android.permission.GET_TASKS"/>

下面是创建悬浮窗的方法:

[java] view plain copy

  1. private boolean isAdded = false; // 是否已增加悬浮窗
  2. private static WindowManager wm;
  3. private static WindowManager.LayoutParams params;
  4. private Button btn_floatView;

[java] view plain copy

  1. /**
  2. * 创建悬浮窗
  3. */
  4. private void createFloatView() {
  5. btn_floatView = new Button(getApplicationContext());
  6. btn_floatView.setText("悬浮窗");
  7. wm = (WindowManager) getApplicationContext()
  8. .getSystemService(Context.WINDOW_SERVICE);
  9. params = new WindowManager.LayoutParams();
  10. // 设置window type
  11. params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
  12. /*
  13. * 如果设置为params.type = WindowManager.LayoutParams.TYPE_PHONE;
  14. * 那么优先级会降低一些, 即拉下通知栏不可见
  15. */
  16. params.format = PixelFormat.RGBA_8888; // 设置图片格式,效果为背景透明
  17. // 设置Window flag
  18. params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
  19. | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
  20. /*
  21. * 下面的flags属性的效果形同“锁定”。
  22. * 悬浮窗不可触摸,不接受任何事件,同时不影响后面的事件响应。
  23. wmParams.flags=LayoutParams.FLAG_NOT_TOUCH_MODAL
  24. | LayoutParams.FLAG_NOT_FOCUSABLE
  25. | LayoutParams.FLAG_NOT_TOUCHABLE;
  26. */
  27. // 设置悬浮窗的长得宽
  28. params.width = 100;
  29. params.height = 100;
  30. // 设置悬浮窗的Touch监听
  31. btn_floatView.setOnTouchListener(new OnTouchListener() {
  32. int lastX, lastY;
  33. int paramX, paramY;
  34. public boolean onTouch(View v, MotionEvent event) {
  35. switch(event.getAction()) {
  36. case MotionEvent.ACTION_DOWN:
  37. lastX = (int) event.getRawX();
  38. lastY = (int) event.getRawY();
  39. paramX = params.x;
  40. paramY = params.y;
  41. break;
  42. case MotionEvent.ACTION_MOVE:
  43. int dx = (int) event.getRawX() - lastX;
  44. int dy = (int) event.getRawY() - lastY;
  45. params.x = paramX + dx;
  46. params.y = paramY + dy;
  47. // 更新悬浮窗位置
  48. wm.updateViewLayout(btn_floatView, params);
  49. break;
  50. }
  51. return true;
  52. }
  53. });
  54. wm.addView(btn_floatView, params);
  55. isAdded = true;
  56. }

做完这步,基本上就可以在桌面显示一个悬浮窗并且可以自由拖动了。

如果想要控制它在桌面显示,而进入到别的应用程序时隐藏它的话,就需要用一个后台运行的Service来实现了。

首先需要先获取到手机上的桌面程序的包名(桌面程序指的是按下HOME键所列出的程序,如go桌面等):

[java] view plain copy

  1. /**
  2. * 获得属于桌面的应用的应用包名称
  3. * @return 返回包含所有包名的字符串列表
  4. */
  5. private List<String> getHomes() {
  6. List<String> names = new ArrayList<String>();
  7. PackageManager packageManager = this.getPackageManager();
  8. // 属性
  9. Intent intent = new Intent(Intent.ACTION_MAIN);
  10. intent.addCategory(Intent.CATEGORY_HOME);
  11. List<ResolveInfo> resolveInfo = packageManager.queryIntentActivities(intent,
  12. PackageManager.MATCH_DEFAULT_ONLY);
  13. for(ResolveInfo ri : resolveInfo) {
  14. names.add(ri.activityInfo.packageName);
  15. }
  16. return names;
  17. }

接着是判断当前运行的Activity是否为桌面应用程序,这里需要用到ActivityManager:

[java] view plain copy

  1. /**
  2. * 判断当前界面是否是桌面
  3. */
  4. public boolean isHome(){
  5. if(mActivityManager == null) {
  6. mActivityManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
  7. }
  8. List<RunningTaskInfo> rti = mActivityManager.getRunningTasks(1);
  9. return homeList.contains(rti.get(0).topActivity.getPackageName());
  10. }

有了上面两个方法,就可以实现这个功能了。只不过我们需要定时去判断,例如可以用一个Handler每一秒去检查一次:

[java] view plain copy

  1. private Handler mHandler = new Handler() {
  2. @Override
  3. public void handleMessage(Message msg) {
  4. switch(msg.what) {
  5. case HANDLE_CHECK_ACTIVITY:
  6. if(isHome()) {
  7. if(!isAdded) {
  8. wm.addView(btn_floatView, params);
  9. isAdded = true;
  10. }
  11. } else {
  12. if(isAdded) {
  13. wm.removeView(btn_floatView);
  14. isAdded = false;
  15. }
  16. }
  17. mHandler.sendEmptyMessageDelayed(HANDLE_CHECK_ACTIVITY, 1000);
  18. break;
  19. }
  20. }
  21. };

在我的Demo中,悬浮窗都是通过Service来控制的,那么我的启动与隐藏就都扔给Service处理就OK。

[java] view plain copy

  1. public void onClick(View v) {
  2. switch(v.getId()) {
  3. case R.id.btn_show:
  4. Intent show = new Intent(this, FloatingWindowService.class);
  5. show.putExtra(FloatingWindowService.OPERATION, FloatingWindowService.OPERATION_SHOW);
  6. startService(show);
  7. break;
  8. case R.id.btn_hide:
  9. Intent hide = new Intent(this, FloatingWindowService.class);
  10. hide.putExtra(FloatingWindowService.OPERATION, FloatingWindowService.OPERATION_HIDE);
  11. startService(hide);
  12. break;
  13. }
  14. }

在Service里的onStart方法中,只需要根据传过来的操作参数,对handler检查进行操作即可。

[java] view plain copy

  1. @Override
  2. public void onStart(Intent intent, int startId) {
  3. super.onStart(intent, startId);
  4. int operation = intent.getIntExtra(OPERATION, OPERATION_SHOW);
  5. switch(operation) {
  6. case OPERATION_SHOW:
  7. mHandler.removeMessages(HANDLE_CHECK_ACTIVITY);
  8. mHandler.sendEmptyMessage(HANDLE_CHECK_ACTIVITY);
  9. break;
  10. case OPERATION_HIDE:
  11. mHandler.removeMessages(HANDLE_CHECK_ACTIVITY);
  12. break;
  13. }
  14. }

另外:需要增加以下权限!!

[html] view plain copy

  1. <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
  2. <uses-permission android:name="android.permission.GET_TASKS"/>
时间: 2024-11-06 15:52:40

悬浮窗的另外一种使用的相关文章

Android 悬浮窗各机型各系统适配大全

这篇博客主要介绍的是 Android 主流各种机型和各种版本的悬浮窗权限适配,但是由于碎片化的问题,所以在适配方面也无法做到完全的主流机型适配,这个需要大家的一起努力,这个博客的名字永远都是一个将来时,感兴趣或者找到其他机型适配方法的请留言告诉我,或者加群544645972一起交流一下,非常感谢~ 相关权限请看我的另一篇博客:android permission权限与安全机制解析(下),或者关于权限的案例使用:android WindowManager解析与骗取QQ密码案例分析. 转载请注明出处

悬浮窗2种方式

main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" andr

(转载)简易的可拖动的桌面悬浮窗效果

本文转载自:http://www.cnblogs.com/xqxacm/p/4918470.html 首先,我们需要知道,悬浮窗分为两种:Activity级别的悬浮窗,系统级别的悬浮窗 Activity级别的悬浮窗跟随所属Activity的生命周期而变化,而系统级别的悬浮窗则可以脱离Activity而存在. 由此可知,要实现360手机卫士那样的悬浮窗效果,就需要使用系统级别的悬浮窗 下面学习实现桌面悬浮窗效果的代码步骤: 1.配置清单文件AndroidManifest.xml 中 添加系统悬浮窗

自定义水波球清理内存的悬浮窗小工具

一.概述 现在一些手机管家都会有一个用来清理内存的悬浮窗小工具,感觉挺实用的,就自己做了一个.首先介绍一下这个工具的功能,除了可以清理内存,还有调节手机屏幕亮度.手电筒.无线网.移动数据.蓝牙.GPS开关的功能.先上图,感受一波: 清理手机内存     一些常用功能的开关 二.功能实现 1.悬浮窗     MainActivity只有两个按钮,控制悬浮窗的打开和关闭.这里我是用Service去控制的.下面我把FloatWindowService的代码贴出来: public class Float

Android Widget和悬浮窗 原理

1.简介 Android widget是桌面插件,在android系统应用开发层面有特殊用途.AppWidget是把一个进程的控件嵌入到别外一个进程的窗口里的一种方法.悬浮窗的效果与Widget很类似,但是它比Widget要灵活的多. 2.详解 1.widget 2.悬浮窗体 3.实例 实例不介绍了,直接下载吧. 下载地址 3.总结 悬浮窗体和桌面插件对应用有非常重要的意思,笔者在此简单描述.

突破小米悬浮窗权限控制--不需要权限的悬浮窗

突破小米悬浮窗权限控制–不需要权限的悬浮窗 在上一篇文章讲了Android的Toast拓展,在原生Toast基础上对显示时长和显示动画做了二次封装,强化了Toast的部分功能.也分析了对于二次封装的ExToast设计原理,以及Toast的关键点.如果不了解的可以看看下面的链接. Toast拓展–自定义显示时间和动画 常用悬浮窗与Toast 之前分析过,Toast其实就是系统悬浮窗的一种,那它跟常用的系统悬浮窗有什么区别呢? 先看一下常用的Andoird系统悬浮窗写法: // 获取应用的Conte

Android无需权限显示悬浮窗, 兼谈逆向分析app

最近UC浏览器中文版出了一个快速搜索的功能, 在使用其他app的时候, 如果复制了一些内容, 屏幕顶部会弹一个窗口, 提示一些操作, 点击后跳转到UC, 显示这个悬浮窗不需要申请android.permission.SYSTEM_ALERT_WINDOW权限. 如下图, 截图是在使用Chrome时截的, 但是屏幕顶部却有UC的view浮在屏幕上. 我使用的是小米, 我并没有给UC授悬浮窗权限, 所以我看到这个悬浮窗时是很震惊的. 截图 悬浮窗原理 做过悬浮窗功能的人都知道, 要想显示悬浮窗, 要

Android好奇宝宝_05_PopupWindow与悬浮窗

这一篇讲讲PopupWindow与悬浮窗之间那些不得不说的故事. 之所以把PopupWindow与悬浮窗这两个放到一起讲,是因为这两个的实现原理基本是一致的,只是有点不同而已. 原理: 使用系统服务(WindowManagerService)将要显示的View添加进Window中. WindowManagerService和ActivityManagerService是Android系统中两个最重要的服务,其中一个管理窗口显示,一个管理四大组件. ActivityManagerService这里

VC++玩转炫酷悬浮窗1---悬浮窗的实现

?? 目标实现像迅雷那样炫酷的悬浮窗.计划&方案首先第一步要实现一个悬浮窗,窗体无边框,能够随意拖动.对于一个窗体来说,只有我们把鼠标放到标题栏中才进入到拖拽模式.由于是无边框的窗体,默认是不能够移动的.我们尝试用两种办法使其跟随鼠标移动.一个是用OnNcHitTest函数,另一个是在OnLButtonDown时发消息.实践一. OnNcHitTest方案这个CWnd类的一个方法,我们可以捕捉鼠标点击的坐标,然后将其HTCLIENT结果偷换成HTCAPTION,这样就可以让系统误以为鼠标左键点击