欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2023-12-15 11:41:04
用过新版本android 360手机助手都人都对 360中只在桌面显示一个小小悬浮窗口羡慕不已吧? 其实实现这种功能,主要有两步: 1.判断当前显示的是为桌面。这个内容我在...
用过新版本android 360手机助手都人都对 360中只在桌面显示一个小小悬浮窗口羡慕不已吧?
其实实现这种功能,主要有两步:
1.判断当前显示的是为桌面。这个内容我在前面的帖子里面已经有过介绍,如果还没看过的赶快稳步看一下哦。
2.使用windowmanager往最顶层添加一个view
.这个知识点就是为本文主要讲解的内容哦。在本文的讲解中,我们还会讲到下面的知识点:
a.如果获取到状态栏的高度
b.悬浮窗口的拖动
c.悬浮窗口的点击事件
有开始之前,我们先来看一下效果图:
android 添加随意拖动的桌面悬浮窗口 
接下来我们来看看floatview的代码:
复制代码 代码如下:

public class floatview extends imageview{
private float mtouchx;
private float mtouchy;
private float x;
private float y;
private float mstartx;
private float mstarty;
private onclicklistener mclicklistener;
private windowmanager windowmanager = (windowmanager) getcontext()
.getapplicationcontext().getsystemservice(context.window_service);
// 此windowmanagerparams变量为获取的全局变量,用以保存悬浮窗口的属性
private windowmanager.layoutparams windowmanagerparams = ((floatapplication) getcontext()
.getapplicationcontext()).getwindowparams();
public floatview(context context) {
super(context);
}
@override
public boolean ontouchevent(motionevent event) {
//获取到状态栏的高度
rect frame = new rect();
getwindowvisibledisplayframe(frame);
int statusbarheight = frame.top;
system.out.println("statusbarheight:"+statusbarheight);
// 获取相对屏幕的坐标,即以屏幕左上角为原点
x = event.getrawx();
y = event.getrawy() - statusbarheight; // statusbarheight是系统状态栏的高度
log.i("tag", "currx" + x + "====curry" + y);
switch (event.getaction()) {
case motionevent.action_down: // 捕获手指触摸按下动作
// 获取相对view的坐标,即以此view左上角为原点
mtouchx = event.getx();
mtouchy = event.gety();
mstartx = x;
mstarty = y;
log.i("tag", "startx" + mtouchx + "====starty"
+ mtouchy);
break;
case motionevent.action_move: // 捕获手指触摸移动动作
updateviewposition();
break;
case motionevent.action_up: // 捕获手指触摸离开动作
updateviewposition();
mtouchx = mtouchy = 0;
if ((x - mstartx) < 5 && (y - mstarty) < 5) {
if(mclicklistener!=null) {
mclicklistener.onclick(this);
}
}
break;
}
return true;
}
@override
public void setonclicklistener(onclicklistener l) {
this.mclicklistener = l;
}
private void updateviewposition() {
// 更新浮动窗口位置参数
windowmanagerparams.x = (int) (x - mtouchx);
windowmanagerparams.y = (int) (y - mtouchy);
windowmanager.updateviewlayout(this, windowmanagerparams); // 刷新显示
}
}

代码解释
int statusbarheight = frame.top;
为获取状态栏的高度,为什么在event.getrawy()的时候减去状态栏的高度呢?
因为我们的悬浮窗口不可能显示到状态栏中去,而后getrawy为获取到屏幕原点的距离。当我们屏幕处于全屏模式时,获取到的状态栏高度会变成0
(x - mstartx) < 5 && (y - mstarty) < 5
如果我们在触摸过程中,移动距离少于5 ,则视为点击,触发点击的回调。
另外我们需要自定义一个application:
复制代码 代码如下:

public class floatapplication extends application {
private windowmanager.layoutparams windowparams = new windowmanager.layoutparams();
public windowmanager.layoutparams getwindowparams() {
return windowparams;
}
}

代码解释
自定义application的目的是为了保存windowparams的值 ,因为我们在拖动悬浮窗口的时候,如果每次都重新new一个layoutparams的话,在update
的时候会在异常发现。
windowparams的值也不一定非得在自定义application里面来保存,只要是全局的都行。
最后我们再来看看activity中的实现。
复制代码 代码如下:

public class mainactivity extends activity implements onclicklistener{
private windowmanager windowmanager = null;
private windowmanager.layoutparams windowmanagerparams = null;
private floatview floatview = null;
@override
public void oncreate(bundle savedinstancestate) {
super.oncreate(savedinstancestate);
requestwindowfeature(window.feature_no_title);//取消标题栏
getwindow().setflags(windowmanager.layoutparams. flag_fullscreen ,
windowmanager.layoutparams. flag_fullscreen);//全屏
setcontentview(r.layout.activity_main);
createview();
}
@override
public boolean oncreateoptionsmenu(menu menu) {
getmenuinflater().inflate(r.menu.activity_main, menu);
return true;
}
public void ondestroy() {
super.ondestroy();
// 在程序退出(activity销毁)时销毁悬浮窗口
windowmanager.removeview(floatview);
}
private void createview() {
floatview = new floatview(getapplicationcontext());
floatview.setonclicklistener(this);
floatview.setimageresource(r.drawable.ic_launcher); // 这里简单的用自带的icon来做演示
// 获取windowmanager
windowmanager = (windowmanager) getapplicationcontext().getsystemservice(context.window_service);
// 设置layoutparams(全局变量)相关参数
windowmanagerparams = ((floatapplication) getapplication()).getwindowparams();
windowmanagerparams.type = layoutparams.type_phone; // 设置window type
windowmanagerparams.format = pixelformat.rgba_8888; // 设置图片格式,效果为背景透明
// 设置window flag
windowmanagerparams.flags = layoutparams.flag_not_touch_modal
| layoutparams.flag_not_focusable;
/*
* 注意,flag的值可以为:
* layoutparams.flag_not_touch_modal 不影响后面的事件
* layoutparams.flag_not_focusable 不可聚焦
* layoutparams.flag_not_touchable 不可触摸
*/
// 调整悬浮窗口至左上角,便于调整坐标
windowmanagerparams.gravity = gravity.left | gravity.top;
// 以屏幕左上角为原点,设置x、y初始值
windowmanagerparams.x = 0;
windowmanagerparams.y = 0;
// 设置悬浮窗口长宽数据
windowmanagerparams.width = layoutparams.wrap_content;
windowmanagerparams.height = layoutparams.wrap_content;
// 显示myfloatview图像
windowmanager.addview(floatview, windowmanagerparams);
}
public void onclick(view v) {
toast.maketext(this, "clicked", toast.length_short).show();
}
}

代码解释
在activity中我们主要是添加悬浮窗,并且设置他的位置。另外需要注意flags的应用:
layoutparams.flag_not_touch_modal 不影响后面的事件
layoutparams.flag_not_focusable 不可聚焦
layoutparams.flag_not_touchable 不可触摸
最后我们在ondestroy()中移除到悬浮窗口。所以,我们测试的时候,记得按home键来切换到桌面。
最后千万记得,在androidmanifest.xml中来申明我们需要用到的android.permission.system_alert_window权限
并且记得申明我们自定义的application哦。
androidmanifest.xml代码如下
复制代码 代码如下:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.krislq.floating"
android:versioncode="1"
android:versionname="1.0" >
<uses-sdk
android:minsdkversion="8"
android:targetsdkversion="15" />
<uses-permission android:name="android.permission.system_alert_window" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/apptheme" android:name="floatapplication">
<activity
android:name=".mainactivity"
android:label="@string/title_activity_main" >
<intent-filter>
<action android:name="android.intent.action.main" />
<category android:name="android.intent.category.launcher" />
</intent-filter>
</activity>
</application>
</manifest>

上一篇:

下一篇: