当前位置: 代码迷 >> Android >> 简易的可拖动的圆桌面悬浮窗效果Demo
  详细解决方案

简易的可拖动的圆桌面悬浮窗效果Demo

热度:115   发布时间:2016-04-27 22:27:45.0
简易的可拖动的桌面悬浮窗效果Demo

首先,我们需要知道,悬浮窗分为两种:Activity级别的悬浮窗,系统级别的悬浮窗

Activity级别的悬浮窗跟随所属Activity的生命周期而变化,而系统级别的悬浮窗则可以脱离Activity而存在。

 

由此可知,要实现360手机卫士那样的悬浮窗效果,就需要使用系统级别的悬浮窗

 

下面学习实现桌面悬浮窗效果的代码步骤:

Demo描述,悬浮窗为一个ImageView ,可以在桌面 ,任意应用,锁屏上方任意移动

 

1、配置清单文件AndroidManifest.xml 中 添加系统悬浮窗的权限

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

 

2、开始Activity代码的编写

 先看成员变量:

    private WindowManager.LayoutParams lp = new WindowManager.LayoutParams();    private static WindowManager windowManager;    private static ImageView imageView;

 onCreate()方法:

获取WindwoManager对象,该对象是系统级别的

windowManager = (WindowManager) getApplication().getSystemService(WINDOW_SERVICE);

使用WindowManager可以显示在其他应用最上层,甚至手机桌面最上层显示窗口。

 

3、添加一个UI空间,作为悬浮窗的内容 ,当然Demo是一个ImageView作为悬浮窗内容,实际项目中就需要用复杂View,ViewGroup来扩展功能了

     
     //注意,悬浮窗只有一个,而当打开应用的时候才会产生悬浮窗,所以要判断悬浮窗是否已经存在,
     if
(imageView != null){ windowManager.removeView(imageView); } // 使用Application context 创建UI控件,避免Activity销毁导致上下文出现问题,因为现在的悬浮窗是系统级别的,不依赖与Activity存在    imageView = new ImageView(getApplicationContext()); imageView.setImageResource(R.mipmap.normal);

 

4、设置系统级别的悬浮窗的参数,保证悬浮窗悬在手机桌面上

     lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT                  |WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;        lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE                  |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
//TYPE_SYSTEM_ALERT  系统提示,它总是出现在应用程序窗口之上
//TYPE_SYSTEM_OVERLAY 系统顶层窗口。显示在其他一切内容之上。此窗口不能获得输入焦点,否则影响锁屏
// FLAG_NOT_FOCUSABLE 悬浮窗口较小时,后面的应用图标由不可长按变为可长按,不设置这个flag的话,home页的划屏会有问题
// FLAG_NOT_TOUCH_MODAL不阻塞事件传递到后面的窗口

关于 WindowManager.LayoutParams 的详解 请参考:Android中WindowManager.LayoutParams类详解

5、悬浮窗默认显示的位置
 lp.gravity = Gravity.LEFT|Gravity.TOP;  //显示在屏幕左上角

 

6、悬浮窗相对5默认位置的位置差和悬浮窗宽高设置

     //显示位置与指定位置的相对位置差        lp.x = 0;        lp.y = 0;        //悬浮窗的宽高        lp.width = WindowManager.LayoutParams.WRAP_CONTENT;        lp.height = WindowManager.LayoutParams.WRAP_CONTENT;

 

7、设置悬浮窗背景透明

lp.format = PixelFormat.TRANSPARENT;

 

8、将悬浮窗添加到WindowManager对象中

 windowManager.addView(imageView,lp);

 

9.设置悬浮窗的响应事件

 这里为移动悬浮窗操作,可以自己扩展添加点击等响应事件

imageView.setOnTouchListener(new View.OnTouchListener() {            private float lastX; //上一次位置的X.Y坐标            private float lastY;            private float nowX;  //当前移动位置的X.Y坐标            private float nowY;            private float tranX; //悬浮窗移动位置的相对值            private float tranY;            @Override            public boolean onTouch(View v, MotionEvent event) {                boolean ret = false;                switch (event.getAction()){                    case MotionEvent.ACTION_DOWN:                        // 获取按下时的X,Y坐标                        lastX = event.getRawX();                        lastY = event.getRawY();                        ret = true;                        break;                    case MotionEvent.ACTION_MOVE:                        // 获取移动时的X,Y坐标                        nowX = event.getRawX();                        nowY = event.getRawY();                        // 计算XY坐标偏移量                        tranX = nowX - lastX;                        tranY = nowY - lastY;                        // 移动悬浮窗                        lp.x += tranX;                        lp.y += tranY;                        //更新悬浮窗位置                        windowManager.updateViewLayout(imageView,lp);                        //记录当前坐标作为下一次计算的上一次移动的位置坐标                        lastX = nowX;                        lastY = nowY;                        break;                    case MotionEvent.ACTION_UP:                        break;                }                return ret;            }        });

10、扩展移除悬浮窗功能

11、效果图:


完整代码:
注意添加权限!!!
  1 package com.xqx.window.app;  2   3 import android.app.Activity;  4 import android.graphics.PixelFormat;  5 import android.os.Bundle;  6 import android.view.*;  7 import android.widget.ImageView;  8   9 /** 10  * 系统级别悬浮窗,可以在手机桌面上显示的悬浮窗 11  */ 12 public class FloatWindowActivity extends Activity { 13  14     private WindowManager.LayoutParams lp = new WindowManager.LayoutParams(); 15     private static WindowManager windowManager; 16     private static ImageView imageView; 17  18     @Override 19     protected void onCreate(Bundle savedInstanceState) { 20         super.onCreate(savedInstanceState); 21         setContentView(R.layout.activity_float_window); 22  23         // 1、获取系统级别的WindowManager 24         windowManager = (WindowManager) getApplication().getSystemService(WINDOW_SERVICE); 25  26         // 判断UI控件是否存在,存在则移除,确保开启任意次应用都只有一个悬浮窗 27         if (imageView != null){ 28             windowManager.removeView(imageView); 29         } 30         // 2、使用Application context 创建UI控件,避免Activity销毁导致上下文出现问题 31         imageView = new ImageView(getApplicationContext()); 32         imageView.setImageResource(R.mipmap.normal); 33  34  35         // 3、设置系统级别的悬浮窗的参数,保证悬浮窗悬在手机桌面上 36         // 系统级别需要指定type 属性 37         // TYPE_SYSTEM_ALERT 允许接收事件 38         // TYPE_SYSTEM_OVERLAY 悬浮在系统上 39         // 注意清单文件添加权限 40  41         //系统提示。它总是出现在应用程序窗口之上。 42         lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT 43                   |WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY; 44  45         // FLAG_NOT_TOUCH_MODAL不阻塞事件传递到后面的窗口 46         // FLAG_NOT_FOCUSABLE 悬浮窗口较小时,后面的应用图标由不可长按变为可长按,不设置这个flag的话,home页的划屏会有问题 47         lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 48                   |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; 49  50         //悬浮窗默认显示的位置 51         lp.gravity = Gravity.LEFT|Gravity.TOP; 52         //显示位置与指定位置的相对位置差 53         lp.x = 0; 54         lp.y = 0; 55         //悬浮窗的宽高 56         lp.width = WindowManager.LayoutParams.WRAP_CONTENT; 57         lp.height = WindowManager.LayoutParams.WRAP_CONTENT; 58  59         lp.format = PixelFormat.TRANSPARENT; 60         windowManager.addView(imageView,lp); 61  62         //设置悬浮窗监听事件 63         imageView.setOnTouchListener(new View.OnTouchListener() { 64             private float lastX; //上一次位置的X.Y坐标 65             private float lastY; 66             private float nowX;  //当前移动位置的X.Y坐标 67             private float nowY; 68             private float tranX; //悬浮窗移动位置的相对值 69             private float tranY; 70  71             @Override 72             public boolean onTouch(View v, MotionEvent event) { 73                 boolean ret = false; 74                 switch (event.getAction()){ 75                     case MotionEvent.ACTION_DOWN: 76                         // 获取按下时的X,Y坐标 77                         lastX = event.getRawX(); 78                         lastY = event.getRawY(); 79                         ret = true; 80                         break; 81                     case MotionEvent.ACTION_MOVE: 82                         // 获取移动时的X,Y坐标 83                         nowX = event.getRawX(); 84                         nowY = event.getRawY(); 85                         // 计算XY坐标偏移量 86                         tranX = nowX - lastX; 87                         tranY = nowY - lastY; 88                         // 移动悬浮窗 89                         lp.x += tranX; 90                         lp.y += tranY; 91                         //更新悬浮窗位置 92                         windowManager.updateViewLayout(imageView,lp); 93                         //记录当前坐标作为下一次计算的上一次移动的位置坐标 94                         lastX = nowX; 95                         lastY = nowY; 96                         break; 97                     case MotionEvent.ACTION_UP: 98                         break; 99                 }100                 return ret;101             }102         });103     }104 105 }
FloatWindowActivity.java

 






  相关解决方案