Android实现自由拖动并显示文字的悬浮框
更新时间:2021年01月26日 17:18:00 作者:化作孤岛的瓜
这篇文章主要为大家详细介绍了Android实现自由拖动并显示文字的悬浮框,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
项目中需要实现一个状态显示的悬浮框,要求可以设置两种模式:拖动模式和不可拖动模式。
实现效果图如下:
实现步骤:
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; } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
您可能感兴趣的文章:
相关文章
详解Flutter中StatefulBuilder组件的使用
StatefulBuilder小部件可以在这些区域的状态发生变化时仅重建某些小区域而无需付出太多努力。本文将来详细讲讲它的使用,需要的可以参考一下2022-05-05Android App中实现可以双击放大和缩小图片功能的实例
这篇文章主要介绍了Android App中实现可以双击放大和缩小图片功能的实例,文中的例子不能做到逐级放大但可以做到边界控制和以触摸点为中心进行放大,需要的朋友可以参考下2016-03-03Android BLE 蓝牙开发之实现扫码枪基于BLESSED开发
这篇文章主要介绍了Android BLE 蓝牙开发之实现扫码枪基于BLESSED开发,示例代码介绍了第三方库BLESSED for Android的使用,需要的朋友可以参考下2022-03-03
最新评论