Android实现*拖动并显示文字的悬浮框
程序员文章站
2022-03-13 09:09:58
项目中需要实现一个状态显示的悬浮框,要求可以设置两种模式:拖动模式和不可拖动模式。实现效果图如下:实现步骤:1.首先要设置该悬浮框的基本属性:/** * 显示弹出框 * * @param con...
项目中需要实现一个状态显示的悬浮框,要求可以设置两种模式:拖动模式和不可拖动模式。
实现效果图如下:
实现步骤:
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; } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。