Android实现自由拖动并显示文字的悬浮框
- 作者: 低吊射滑友内含
- 来源: 51数据库
- 2021-06-30
项目中需要实现一个状态显示的悬浮框,要求可以设置两种模式:拖动模式和不可拖动模式。
实现效果图如下:

实现步骤:
1.首先要设置该悬浮框的基本属性:
/**
* 显示弹出框
*
* @param context
*/
@suppresswarnings("wrongconstant")
public static void showpopupwindow(final context context, string showtxt) {
if (isshown) {
return;
}
isshown = true;
// 获取windowmanager
mwindowmanager = (windowmanager) context
.getsystemservice(context.window_service);
mview = setupview(context, showtxt);
params = new windowmanager.layoutparams();
// 类型,系统提示以及它总是出现在应用程序窗口之上。
params.type = windowmanager.layoutparams.type_system_alert |
windowmanager.layoutparams.type_system_overlay;
// 设置flag
int flags = cantouchflags;
// | windowmanager.layoutparams.flag_not_focusable;
// 如果设置了windowmanager.layoutparams.flag_not_focusable,弹出的view收不到back键的事件
params.flags = flags;
// 不设置这个弹出框的透明遮罩显示为黑色
params.format = pixelformat.translucent;
// flag_not_touch_modal不阻塞事件传递到后面的窗口
// 设置 flag_not_focusable 悬浮窗口较小时,后面的应用图标由不可长按变为可长按
// 不设置这个flag的话,home页的划屏会有问题
params.width = layoutparams.wrap_content;
params.height = layoutparams.wrap_content;
params.gravity = gravity.top;
mwindowmanager.addview(mview, params);
}
比较重要的点是要注意设置flags,我这里提供了两种flags以供切换:
private static int cantouchflags = windowmanager.layoutparams.flag_not_focusable | windowmanager.layoutparams.flag_not_touch_modal; private static int nottouchflags = windowmanager.layoutparams.flag_not_focusable| windowmanager.layoutparams.flag_not_touchable;
第一种是可触摸不可聚焦模式,第二种是不可触摸不可聚焦模式。其他的flags可以从api中查阅。
2.设置悬浮框的拖动监听事件:
private static view setupview(final context context, string showtxt) {
view view = layoutinflater.from(context).inflate(r.layout.layout_popwindow,
null);
textview showtv = (textview) view.findviewbyid(r.id.tv_showinpop);
showtv.settext(showtxt);
rl_drag_showinpop = (relativelayout) view.findviewbyid(r.id.rl_drag_showinpop);
rl_drag_showinpop.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;
params.x += tranx;
params.y += trany;
//更新悬浮窗位置
mwindowmanager.updateviewlayout(mview, params);
//记录当前坐标作为下一次计算的上一次移动的位置坐标
lastx = nowx;
lasty = nowy;
break;
case motionevent.action_up:
break;
}
return ret;
}
});
这里要在down的时候记录坐标,move事件中使用修改params坐标进行移动。
3.设置悬浮框文字属性:
public static void setshowtxt(string txt) {
try {
textview showtv = (textview) mview.findviewbyid(r.id.tv_showinpop);
showtv.settext(txt);
mwindowmanager.updateviewlayout(mview, params);
}catch (exception e){
log.d(tag, "setshowtxt: 更新悬浮框错误");
e.printstacktrace();
if(e.getmessage().contains("not attached to window manager")){
mwindowmanager.addview(mview, params);
}
}
}
4.更新悬浮框图片显示:
public static void setshowimg(bitmap bitmap) {
try {
imageview showimg = (imageview) mview.findviewbyid(r.id.iv_showinpop);
showimg.setimagebitmap(bitmap);
mwindowmanager.updateviewlayout(mview, params);
}catch (exception e){
log.d(tag, "setshowtxt: 更新悬浮框错误");
e.printstacktrace();
if(e.getmessage().contains("not attached to window manager")){
mwindowmanager.addview(mview, params);
}
}
}
介绍完毕,整个类都封装好了,代码如下:
/**
* 悬浮窗工具类
* created by pumpkin at 17/3/28
*/
public class windowsuitlity {
private static string tag = windowsuitlity.class.getsimplename();
private static windowmanager mwindowmanager = null;
private static windowmanager.layoutparams params;
public static boolean isshown = false;
private static view mview = null;
/**
* 显示弹出框
*
* @param context
*/
@suppresswarnings("wrongconstant")
public static void showpopupwindow(final context context, string showtxt) {
if (isshown) {
return;
}
isshown = true;
// 获取windowmanager
mwindowmanager = (windowmanager) context
.getsystemservice(context.window_service);
mview = setupview(context, showtxt);
params = new windowmanager.layoutparams();
// 类型,系统提示以及它总是出现在应用程序窗口之上。
params.type = windowmanager.layoutparams.type_system_alert |
windowmanager.layoutparams.type_system_overlay;
// 设置flag
int flags = cantouchflags;
// | windowmanager.layoutparams.flag_not_focusable;
// 如果设置了windowmanager.layoutparams.flag_not_focusable,弹出的view收不到back键的事件
params.flags = flags;
// 不设置这个弹出框的透明遮罩显示为黑色
params.format = pixelformat.translucent;
// flag_not_touch_modal不阻塞事件传递到后面的窗口
// 设置 flag_not_focusable 悬浮窗口较小时,后面的应用图标由不可长按变为可长按
// 不设置这个flag的话,home页的划屏会有问题
params.width = layoutparams.wrap_content;
params.height = layoutparams.wrap_content;
params.gravity = gravity.top;
mwindowmanager.addview(mview, params);
}
private static int cantouchflags = windowmanager.layoutparams.flag_not_focusable
| windowmanager.layoutparams.flag_not_touch_modal;
private static int nottouchflags = windowmanager.layoutparams.flag_not_focusable|
windowmanager.layoutparams.flag_not_touchable;
/**
* 设置是否可响应点击事件
*
* @param istouchable
*/
public static void settouchable(boolean istouchable) {
if (istouchable) {
params.flags = cantouchflags;
} else {
params.flags = nottouchflags;
}
mwindowmanager.updateviewlayout(mview, params);
}
/**
* 隐藏弹出框
*/
public static void hidepopupwindow() {
if (isshown && null != mview) {
mwindowmanager.removeview(mview);
isshown = false;
}
}
public static void setshowtxt(string txt) {
try {
textview showtv = (textview) mview.findviewbyid(r.id.tv_showinpop);
showtv.settext(txt);
mwindowmanager.updateviewlayout(mview, params);
}catch (exception e){
log.d(tag, "setshowtxt: 更新悬浮框错误");
e.printstacktrace();
if(e.getmessage().contains("not attached to window manager")){
mwindowmanager.addview(mview, params);
}
}
}
public static void setshowimg(bitmap bitmap) {
try {
imageview showimg = (imageview) mview.findviewbyid(r.id.iv_showinpop);
showimg.setimagebitmap(bitmap);
mwindowmanager.updateviewlayout(mview, params);
}catch (exception e){
log.d(tag, "setshowtxt: 更新悬浮框错误");
e.printstacktrace();
if(e.getmessage().contains("not attached to window manager")){
mwindowmanager.addview(mview, params);
}
}
}
static relativelayout rl_drag_showinpop;
private static view setupview(final context context, string showtxt) {
view view = layoutinflater.from(context).inflate(r.layout.layout_popwindow,
null);
textview showtv = (textview) view.findviewbyid(r.id.tv_showinpop);
showtv.settext(showtxt);
rl_drag_showinpop = (relativelayout) view.findviewbyid(r.id.rl_drag_showinpop);
rl_drag_showinpop.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;
params.x += tranx;
params.y += trany;
//更新悬浮窗位置
mwindowmanager.updateviewlayout(mview, params);
//记录当前坐标作为下一次计算的上一次移动的位置坐标
lastx = nowx;
lasty = nowy;
break;
case motionevent.action_up:
break;
}
return ret;
}
});
return view;
}
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
推荐阅读
热点文章
android中Bitmap用法(显示,保存,缩放,旋转)实例分析
12
android 仿微信聊天气泡效果实现思路
1
Android的尺度,drawable-xxxxxxx
2
Codeforces Round #656 (Div. 3) (C、D题)
1
Android之handler异步消息处理机制解析
6
GridView中图片显示出现上下间距过大,左右图片显示类似瀑布流的问题
0
AsyncTask的简单使用
5
两个简单Fragment之间的通信(三种方式)
18
uboot修改设置boot参数命令
41
android中实现从相册中一次性获取多张图片与拍照,并将选中的图片显示出来
2
