Android中可自由移动悬浮窗口的实现

大家对悬浮窗概念不会陌生,相信每台电脑桌面的右上角都会有这么一个东西,它总是出现在所有页面的顶端(Top Show)。但在Android平台中如何实现这样的效果呢?先来看一看效果图。

看见在Google搜索框上面的那个Icon图片了嘛。下面我就来详细介绍一下在Android平台下悬浮窗口的实现,并让它能够随手指的触摸而移动。

一、实现原理及移动思路

调用WindowManager,并设置WindowManager.LayoutParams的相关属性,通过WindowManager的addView方法创建View,这样产生出来的View根据WindowManager.LayoutParams属性不同,效果也就不同了。比如创建系统顶级窗口,实现悬浮窗口效果!然后通过覆写悬浮View中onTouchEvent方法来改变windowMananager.LayoutParams中x和y的值来实现自由移动悬浮窗口。

二、示例代码

先来看一看悬浮View的代码,这里用一个ImageView作为演示

 1 public class MyFloatView extends ImageView {
 2
 3     private float mTouchStartX;
 4
 5     private float mTouchStartY;
 6
 7     private float x;
 8
 9     private float y;
10
11
12
13     private WindowManager wm=(WindowManager)getContext().getApplicationContext().getSystemService("window");
14
15     //此wmParams变量为获取的全局变量,用以保存悬浮窗口的属性
16 09
17     private WindowManager.LayoutParams wmParams = ((MyApplication)getContext().getApplicationContext()).getMywmParams();
18 10
19
20 11
21     public MyFloatView(Context context) {
22 12
23         super(context);
24 13
25         // TODO Auto-generated constructor stub
26 14
27     }
28 15
29
30 16
31      @Override
32 17
33      public boolean onTouchEvent(MotionEvent event) {
34 18
35          //获取相对屏幕的坐标,即以屏幕左上角为原点
36 19
37          x = event.getRawX();
38 20
39          y = event.getRawY()-25;   //25是系统状态栏的高度
40 21
41          Log.i("currP", "currX"+x+"====currY"+y);
42 22
43          switch (event.getAction()) {
44 23
45             case MotionEvent.ACTION_DOWN:    //捕获手指触摸按下动作
46 24
47                 //获取相对View的坐标,即以此View左上角为原点
48 25
49                 mTouchStartX =  event.getX();
50 26
51                     mTouchStartY =  event.getY();
52 27
53                 Log.i("startP","startX"+mTouchStartX+"====startY"+mTouchStartY);
54 28
55                 break;
56 29
57
58 30
59             case MotionEvent.ACTION_MOVE:   //捕获手指触摸移动动作
60 31
61                 updateViewPosition();
62 32
63                 break;
64 33
65
66 34
67             case MotionEvent.ACTION_UP:    //捕获手指触摸离开动作
68 35
69                 updateViewPosition();
70 36
71                 mTouchStartX=mTouchStartY=0;
72 37
73                 break;
74 38
75             }
76 39
77             return true;
78 40
79         }
80 41
81
82 42
83      private void updateViewPosition(){
84 43
85         //更新浮动窗口位置参数
86 44
87         wmParams.x=(int)( x-mTouchStartX);
88 45
89         wmParams.y=(int) (y-mTouchStartY);
90 46
91         wm.updateViewLayout(this, wmParams);  //刷新显示
92 47
93      }
94 48
95
96 49
97 }

上面的wmParams变量(即WindowManager.LayoutParams)的存储采用了extends Application的方式来创建全局变量,示例代码如下:

 1 public class MyApplication extends Application {
 2 02
 3
 4 03
 5     /**
 6 04
 7      * 创建全局变量
 8 05
 9      * 全局变量一般都比较倾向于创建一个单独的数据类文件,并使用static静态变量
10 06
11      *
12 07
13      * 这里使用了在Application中添加数据的方法实现全局变量
14 08
15      * 注意在AndroidManifest.xml中的Application节点添加android:name=".MyApplication"属性
16 09
17      *
18 10
19      */
20 11
21     private WindowManager.LayoutParams wmParams=newWindowManager.LayoutParams();
22 12
23
24 13
25     public WindowManager.LayoutParams getMywmParams(){
26 14
27         return wmParams;
28 15
29     }
30 16
31 }

再来看一看Activity中的代码:

  1 public class MyFloatViewActivity extends Activity {
  2 02
  3     /** Called when the activity is first created. */
  4 03
  5
  6 04
  7     private WindowManager wm=null;
  8 05
  9     private WindowManager.LayoutParams wmParams=null;
 10 06
 11
 12 07
 13     private MyFloatView myFV=null;
 14 08
 15
 16 09
 17
 18 10
 19     @Override
 20 11
 21     public void onCreate(Bundle savedInstanceState) {
 22 12
 23         super.onCreate(savedInstanceState);
 24 13
 25         setContentView(R.layout.main);
 26 14
 27         //创建悬浮窗口
 28 15
 29         createView();
 30 16
 31
 32 17
 33     }
 34 18
 35
 36 19
 37
 38 20
 39
 40 21
 41     private void createView(){
 42 22
 43         myFV=new MyFloatView(getApplicationContext());
 44 23
 45         myFV.setImageResource(R.drawable.icon);  //这里简单的用自带的Icom来做演示
 46 24
 47         //获取WindowManager
 48 25
 49         wm=(WindowManager)getApplicationContext().getSystemService("window");
 50 26
 51         //设置LayoutParams(全局变量)相关参数
 52 27
 53         wmParams = ((MyApplication)getApplication()).getMywmParams();
 54 28
 55
 56 29
 57          /**
 58 30
 59          *以下都是WindowManager.LayoutParams的相关属性
 60 31
 61          * 具体用途可参考SDK文档
 62 32
 63          */
 64 33
 65         wmParams.type=LayoutParams.TYPE_PHONE;   //设置window type
 66 34
 67         wmParams.format=PixelFormat.RGBA_8888;   //设置图片格式,效果为背景透明
 68 35
 69
 70 36
 71         //设置Window flag
 72 37
 73         wmParams.flags=LayoutParams.FLAG_NOT_TOUCH_MODAL
 74 38
 75                               | LayoutParams.FLAG_NOT_FOCUSABLE;
 76 39
 77         /*
 78 40
 79          * 下面的flags属性的效果形同“锁定”。
 80 41
 81          * 悬浮窗不可触摸,不接受任何事件,同时不影响后面的事件响应。
 82 42
 83          wmParams.flags=LayoutParams.FLAG_NOT_TOUCH_MODAL
 84 43
 85                                | LayoutParams.FLAG_NOT_FOCUSABLE
 86 44
 87                                | LayoutParams.FLAG_NOT_TOUCHABLE;
 88 45
 89         */
 90 46
 91
 92 47
 93
 94 48
 95         wmParams.gravity=Gravity.LEFT|Gravity.TOP;   //调整悬浮窗口至左上角,便于调整坐标
 96 49
 97         //以屏幕左上角为原点,设置x、y初始值
 98 50
 99         wmParams.x=0;
100 51
101         wmParams.y=0;
102 52
103
104 53
105         //设置悬浮窗口长宽数据
106 54
107         wmParams.width=40;
108 55
109         wmParams.height=40;
110 56
111
112 57
113         //显示myFloatView图像
114 58
115         wm.addView(myFV, wmParams);
116 59
117
118 60
119     }
120 61
121
122 62
123     @Override
124 63
125     public void onDestroy(){
126 64
127         super.onDestroy();
128 65
129         //在程序退出(Activity销毁)时销毁悬浮窗口
130 66
131         wm.removeView(myFV);
132 67
133     }
134 68
135 }

最后,别忘了在AndroidManifest.xml中添加权限:

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

这样一个可以置顶显示、悬浮、且可自由移动的窗口就完工了。运行一下,然后按Home键返回桌面试试看(不能点击返回键,演示程序这里设置了销毁窗体)

三、一些说明

WindowManager的方法很简单,基本用到的就三个addView,removeView,updateViewLayout。

而WindowManager.LayoutParams的属性就多了,非常丰富,这个也是关键所在。

这里例举两个window type:

 1 /**
 2 02
 3  * Window type: phone.  These are non-application windows providing
 4 03
 5  * user interaction with the phone (in particular incoming calls).
 6 04
 7  * These windows are normally placed above all applications, but behind
 8 05
 9  * the status bar.
10 06
11  */
12 07
13 public static final int TYPE_PHONE              = FIRST_SYSTEM_WINDOW+2;
14 08
15
16 09
17 /**
18 10
19  * Window type: system window, such as low power alert. These windows
20 11
21  * are always on top of application windows.
22 12
23  */
24 13
25 public static final int TYPE_SYSTEM_ALERT       = FIRST_SYSTEM_WINDOW+3;

可以看出TYPE_SYSTEM_ALERT的显示层次比TYPE_PHONE还要高,有兴趣的可以试一试显示效果哦!

另外关键的window flag:

 1 /** Window flag: this window won‘t ever get focus. */
 2 02
 3 public static final int FLAG_NOT_FOCUSABLE      = 0x00000008;
 4 03
 5
 6 04
 7 /** Window flag: this window can never receive touch events. */
 8 05
 9 public static final int FLAG_NOT_TOUCHABLE      = 0x00000010;
10 06
11
12 07
13 /** Window flag: Even when this window is focusable (its
14 08
15  * {@link #FLAG_NOT_FOCUSABLE is not set), allow any pointer events
16 09
17  * outside of the window to be sent to the windows behind it.  Otherwise
18 10
19  * it will consume all pointer events itself, regardless of whether they
20 11
21  * are inside of the window. */
22 12
23 public static final int FLAG_NOT_TOUCH_MODAL    = 0x00000020;

详细的可以看一下这里

最后,关于Android平台下的悬浮窗口,有人说很不友好,有人很困惑哪里会用到。事实上,在一些软件里面,悬浮窗口的设计给它们带来了很大的优势,比如流量监控,比如歌词显示。

给出源码包下载

转自:http://blog.csdn.net/fancylovejava/article/details/17891977

时间: 2024-10-19 12:55:37

Android中可自由移动悬浮窗口的实现的相关文章

Android使用WindowManager实现悬浮窗口

原文地址:http://www.3g-edu.org/news/art027.htm 下面就介绍一下如何通过WindowManager来实现这个效果. 通过WindowManager的addView()方法,并设置WindowManager.LayoutParams的相关属性,就可以往WindowManager中加入所需要的View,而根据WindowManager.LayoutParams属性不同,也就能实现不同的效果.比如创建系统顶级窗口,实现悬浮窗口效果.如果需要将View从WindowM

android 类似360悬浮窗口实现源码

当我们在手机上安装360安全卫士时,手机屏幕上时刻都会出现一个小浮动窗口,点击该浮动窗口可跳转到安全卫士的操作界面,而且该浮动窗口不受其他activity的覆盖影响仍然可见(多米音乐也有相关的和主界面交互的悬浮小窗口).它能悬浮在手机桌面,且不受Activity界面的影响,说明该悬浮窗口是不隶属于Activity界面的,也就是说,他是隶属于启动它的应用程序所在进程.如360App所在的应用进程,当杀掉它所在的应用进程时,它才会消失.悬浮窗口的实现涉及到WindowManager(基于4.0源码分

Android悬浮窗口的实现

效果图:(悬浮框可拖动) 在项目开发中有一个需求:弹出悬浮窗后,响应悬浮窗的事件再弹出对话框,但是对话框怎么也不显示.也就是说在弹出悬浮框的同时,不能再弹出对话框,可能的原因: 1.悬浮框的焦点在最前面,把对话框挡住了,我们看不到. 2.浮动框限制了对话框的弹出. 解决: 弹出对话框的时候把悬浮框关掉,然后对话框处理完了,把对话框关掉,在重新开启一个悬浮框,把需要的值传进去. 就相关知识详解: 当我们在手机上使用360安全卫士时,手机屏幕上时刻都会出现一个小浮动窗口,点击该浮动窗口可跳转到安全卫

Android中悬浮窗口

调用WindowManager,并设置WindowManager.LayoutParams的相关属性,通过WindowManager的addView方法创建View,这样产生出来的View根据WindowManager.LayoutParams属性不同,效果也就不同了.比如创建系统顶级窗口,实现悬浮窗口效果!WindowManager的方法很简单,基本用到的就三个addView,removeView,updateViewLayout.而WindowManager.LayoutParams的属性就

Android 悬浮窗口

一.创建悬浮窗口步骤    1.实现一个ViewGroup类,作为悬浮窗口的界面类,以便在里面重写onInterceptTouchEvent和onTouchEvent方法,实现移动界面的目的.       在本例中实现了一个FloatLayer类,可以作为通用的类,使用时需要传入WindowManager对象以实现移动窗口. // FloatLayer ~ package com.example.hellofloatingwnd; import static com.ahai.util.Debu

Android 实现顶层窗口、悬浮窗口

1.如图片1所示,在一个Android应用中,除了标题栏和底层的ActionBar的区域,是我们可以操纵的UI区域,那是不是说我们就不能改变除了这两个区域的UI呢?答案是否定的. 比如现在我们希望把一个View放在窗口的最低端显示,通过hierarchyviewer工具我们可以发现最底层的ActionBar是在TestActivity布局的父窗口中设置的,那么我们想通过setContentView(R.layout.activity_main)在activity_main布局文件中设置就无法实现

Android悬浮窗口

FloatService: package com.home.floatwindow; import android.app.Service; import android.content.Context; import android.content.Intent; import android.graphics.PixelFormat; import android.os.IBinder; import android.util.Log; import android.view.Gravit

android中使用PopupWindow实现弹出窗口菜单

结合上篇android中使用ViewPager实现图片拖动,我们实现了点击“帮助”按钮的功能,这一篇则是接着上一篇,让我们一起来完成“我的”按钮的功能,这一功能,则是使用PopupWindow来实现弹出菜单. 再上项目结构图,如图: 从项目结构图可见,我们这里并没有新建新的Activity,因为“我的”按钮和“帮助”是在一个页面的,所以,我们只需新建一个效果图中的,弹出菜单的布局文件即可,即popup_menu.xml,代码如下: Xml代码 <? xml version = "1.0&q

Android中简单活动窗口的切换--Android

本例实现Android中简单Activity窗口切换:借助intent(意图)对应用操作(这里用按钮监听)等的描述,Android根据描述负责找对应的组件,完成组件的调用来实现活动的切换……案例比较简单直接附上代码了哈. 1.建两个Activity类,分别为MainActivity.java和GuideActivity.java…… MainActivity.java(核心文件): package livetelecast.thonlon.example.cn.thonlonliveteleca