Android实现自由拖动并显示文字的悬浮框
作者:化作孤岛的瓜 发布时间:2023-06-08 06:30:39
标签: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;
}
}
来源:https://pumpkin.blog.csdn.net/article/details/71155781


猜你喜欢
- 前面文章介绍了如何使用JAVA的反射机制来调用蓝牙的隐藏API,本文继续来练习JAVA的反射机制,探秘TelephonyManager在Fr
- 之前使用springMVC+spring+mybatis,总是被一些繁琐的xml配置,有时候如果配置出错,还要检查各种xml配置,偶然接触到
- c#开发cad如何预览图块1.定义变量的方法代码如下2. 获取GetDwgImag图像的方法代码3.实现显示DWG文件的方法代码方
- 前言:其实作为一名Java的程序猿,无论你是初学也好,大神也罢,学生管理系统一直都是一个非常好的例子,初学者主要是用数组、List等等来写出
- 本文实例为大家分享了Android封装MVP实现登录注册功能,供大家参考,具体内容如下model包:import com.bwei.mvps
- 什么是JSON?JSON (JavaScript Object Notation) is a lightweight data-interc
- 本人是从事互联网金融行业的,所以会接触到一些金融类的问题,常见的一种就是数字转汉字大小写的问题。所以抽空就写了一个小小的工具类,实现了数字转
- 本文实例为大家分享了android自定义imageview实现圆角图片的具体代码,供大家参考,具体内容如下自定义图片的属性,对图片进行圆角切
- 前段时间学习JDBC,要连接mysql获取数据。按照老师的样例数据,要存一些名字之类的信息,用的都是英文名,我当时就不太想用英文,就把我室友
- springmvc控制登录用户session失效后跳转登录页面,废话不多少了,具体如下:第一步,配置 web.xml <session
- 学会了Paint,Canvas的基本用法之后,我们就可以动手开始实践了,先写个简单的图片加载进度条看看。按照惯例,先看效果图,再决定要不要往
- 使用注解开发在Spring4之后,要使用注解开发,必须要保证aop的包导入了使用注解需要导入context的约束,增加注解的支持<?x
- 安卓系统本身可以很简便的实现分享功能,因为我们只需向startActivity传递一个ACTION_SEND的Intent,系统就为我们弹出
- 本文实例讲述了Android授权访问网页的实现方法,即使用Webview显示OAuth Version 2.a ImplicitGrant方
- 引出泛型我们通过如下的示例,引出为什么泛型的概念。public class Test {public static void main(St
- java 打造阻塞式线程池的实例详解原来以为tiger已经自带了这种线程池,就是在任务数量超出时能够阻塞住投放任务的线程,主要想用在JMS消
- 本文实例讲述了使用adb命令向Android模拟器中导入通讯录联系人的方法。分享给大家供大家参考。具体实现方法如下:使用adb提供的命令,
- 问题描述:idea输入中文,没输入几个拼音就好像自动回车,有时得到几个字母,然后就不能输入拼音了。遇到这个情况就导致输入中文特别困难,可以采
- 在jdk文档中对RandomAccess接口的定义如下: public interface RandomAccess下面是jdk
- 1、创建实体属性标记public class CellAttribute : Attribute {&n