项目中需要实现一个状态显示的悬浮框,要求可以设置两种模式:拖动模式和不可拖动模式。
实现效果图如下:
实现步骤:
1、首先要设置该悬浮框的基本属性:
/**
* 显示弹出框
*
* @param context
*/
@SuppressWarnings("WrongConstant")
publicstaticvoidshowPopupWindow(finalContext context, String showtxt) {
if(isShown) {
return;
}
isShown = true;
// 获取WindowManager
mWindowManager = (WindowManager) context
展开全文
.getSystemService(Context.WINDOW_SERVICE);
mView = setUpView(context, showtxt);
params = newWindowManager.LayoutParams();
// 类型,系统提示以及它总是出现在应用程序窗口之上。
params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT |
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
// 设置flag
intflags = 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以供切换:
privatestaticintcanTouchFlags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
privatestaticintnotTouchFlags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
第一种是可触摸不可聚焦模式,第二种是不可触摸不可聚焦模式。其他的flags可以从api中查阅。
2、设置悬浮框的拖动监听事件:
privatestaticView setUpView(finalContext 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(newView.OnTouchListener() {
privatefloatlastX; //上一次位置的X.Y坐标
privatefloatlastY;
privatefloatnowX; //当前移动位置的X.Y坐标
privatefloatnowY;
privatefloattranX; //悬浮窗移动位置的相对值
privatefloattranY;
@Override
publicbooleanonTouch(View v, MotionEvent event) {
booleanret = false;
switch(event.getAction()) {
caseMotionEvent.ACTION_DOWN:
// 获取按下时的X,Y坐标
lastX = event.getRawX();
lastY = event.getRawY();
ret = true;
break;
caseMotionEvent.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;
caseMotionEvent.ACTION_UP:
break;
}
returnret;
}
});
这里要在down的时候记录坐标,move事件中使用修改params坐标进行移动。
3、设置悬浮框文字属性:
publicstaticvoidsetShowTxt(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、更新悬浮框图片显示:
publicstaticvoidsetShowImg(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
*/
publicclassWindowsUitlity {
privatestaticString TAG = WindowsUitlity.class.getSimpleName();
privatestaticWindowManager mWindowManager = null;
privatestaticWindowManager.LayoutParams params;
publicstaticBoolean isShown = false;
privatestaticView mView = null;
/**
* 显示弹出框
*
* @param context
*/
@SuppressWarnings("WrongConstant")
publicstaticvoidshowPopupWindow(finalContext context, String showtxt) {
if(isShown) {
return;
}
isShown = true;
// 获取WindowManager
mWindowManager = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
mView = setUpView(context, showtxt);
params = newWindowManager.LayoutParams();
// 类型,系统提示以及它总是出现在应用程序窗口之上。
params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT |
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
// 设置flag
intflags = 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);
}
privatestaticintcanTouchFlags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
privatestaticintnotTouchFlags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
/**
* 设置是否可响应点击事件
*
* @param isTouchable
*/
publicstaticvoidsetTouchable(booleanisTouchable) {
if(isTouchable) {
params.flags = canTouchFlags;
} else{
params.flags = notTouchFlags;
}
mWindowManager.updateViewLayout(mView, params);
}
/**
* 隐藏弹出框
*/
publicstaticvoidhidePopupWindow() {
if(isShown && null!= mView) {
mWindowManager.removeView(mView);
isShown = false;
}
}
publicstaticvoidsetShowTxt(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);
}
}
}
publicstaticvoidsetShowImg(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);
}
}
}
staticRelativeLayout rl_drag_showinpop;
privatestaticView setUpView(finalContext 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(newView.OnTouchListener() {
privatefloatlastX; //上一次位置的X.Y坐标
privatefloatlastY;
privatefloatnowX; //当前移动位置的X.Y坐标
privatefloatnowY;
privatefloattranX; //悬浮窗移动位置的相对值
privatefloattranY;
@Override
publicbooleanonTouch(View v, MotionEvent event) {
booleanret = false;
switch(event.getAction()) {
caseMotionEvent.ACTION_DOWN:
// 获取按下时的X,Y坐标
lastX = event.getRawX();
lastY = event.getRawY();
ret = true;
break;
caseMotionEvent.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;
caseMotionEvent.ACTION_UP:
break;
}
returnret;
}
});
returnview;
}
}
头条新闻
▼
尚学堂每周有免费的试听课程,
想学习的同学们,可以先来试听。
参加试听方法:点击阅读原文,提交姓名+电话,课程老师给同学们安排座位,免费试学Java前端课程。
www.029sxt.com
网友评论
最新评论
indowManager.updateViewLayout(mView, params); }catch(Exception e){ Log.d(TAG, "setShowTxt: 更新悬浮框错误"); e.printStackT
returnview; } } 头条新闻▼尚学堂每周有免费的试听课程,想学习的同学们,可以先来试听。参加试听方法:点击阅读原文,提交姓名+电话,课程老师给同学们安排座位,免费试学Java前端课程。www.029sxt.com
ble*/publicstaticvoidsetTouchable(booleanisTouchable) { if(isTouchable) { params.f
showTv.setText(txt); mWindowManager.updateViewLayout(mView, params); }catch(Exception e){ Log.d(TAG, "setShowTxt: 更新悬浮框
wManager mWindowManager = null; privatestaticWindowManager.LayoutParams params; publicsta