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
0
投稿
猜你喜欢
- Selenium IDE 是Firefox 浏览器的一个插件, 它会记录你对Firefox的操作,并且可以回放它的操作。 用法简单,不过我觉
- 前言很多人之前编写Java代码都是用的Eclipse,确实Eclipse是一个很好的工具,熟悉了之后用起来很方便,但是没办法,很多公司都强制
- 批注是一种富文本注释,常用于为指定的Excel单元格添加提示或附加信息。 Free Spire.XLS for Java为开发人员免费提供了
- 实体对象之间相互传值,如:VO对象的值赋给Entity对象,是代码中常用功能,如果通过get、set相互赋值,则很麻烦,借助工具类BeanU
- 前言众所周知在spring boot内,设置session过期时间只需在application.properties内添加server.se
- WPF 如何实现简单放大镜框架使用.NET40;Visual Studio 2019;实现此功能需要用到 VisualBrush&
- 一、Sharding-JDBC简介Sharding-JDBC是Sharding-Sphere的一个产品,它有三个产品,分别是Sharding
- 本文实例讲述了spring AOP的Around增强实现方法。分享给大家供大家参考,具体如下:一 配置<?xml version=&q
- 前言前段时间看到一道面试题:“main函数可以被重载么?”,当时就蒙圈了,怎么还会有这种面试题,现在
- using System.Runtime.InteropServices; using System.Text; publicclass F
- 一 引入考虑实现一种三轴机器人控件。三轴机器人用来将某种工件从一个位置运送到另一个位置。其X轴为手臂轴,可以正向和反向运动,它处于末端,直接
- 内容简介本篇将介绍 Flutter 中如何完成图片上传,以及上传成功后的表单提交。涉及的知识点如下:图片选择插件wechat_assets_
- 本文实例为大家分享了java http token的具体代码,供大家参考,具体内容如下package com.monitoring.comm
- 先新建一个文件夹kun,kun就是类所在的package。新建一个java文件。HelloWorld.java的代码如下:package k
- 前言Elasticsearch是一个非常流行的搜索引擎,已经成为了许多企业的首选解决方案。然而,我们要想成为一个优秀的程序员,就必须掌握各种
- clone() 方法麻烦一些,需要将所有涉及到的类实现声明式接口 Cloneable,并覆盖Object类中的clone()方法,并设置作用
- 摘要:vs2019新鲜出炉,配置opencv又有哪些不一样呢,这个教程将会一步一步的教你如何配置opencv和跑动opencv一个简单的项目
- 问题(1)synchronized的特性?(2)synchronized的实现原理?(3)synchronized是否可重入?(4)sync
- 通常在一份Excel文档中可能包含多个内容不同的工作表,而他们的默认名都为Sheet1、Sheet2、Sheet3等。为了方便我们的查找和操
- 前言java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也不能做出来非常好用,