类似于某鱼、某猫直播平台的悬浮窗功能,能够在APP切换到后台后进行播放直播。
是不是很酷炫?
WindowManager很简单就能实现将一个View悬浮在系统上。
WindowManaget是Android最重要的服务之一,WindowManager是全局唯一的。
其将View和屏幕联系起来,用户的交互操作也传递给它,作为桥梁完成逻辑处理与视图的通讯。
常用的也就三个方法:addView(),removeView(),updateViewLayout()。用于添加、删除、更新视图。
1 . 简单的获取WindowManager对象:
// 获取WindowManager对象
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
2 .获取一个View视图
// 获取一个View
mView = LayoutInflater.from(mContext).inflate(R.layout.window_test, null);
3 .创建WindowManager.LayoutParams
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
// 设置为始终
layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
// 设置弹出的Window不持有焦点
layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
// 大小
layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
// 位置
layoutParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
// 设置背景透明
layoutParams.format = PixelFormat.TRANSLUCENT;
return layoutParams;
4 .显示、隐藏View
// 显示
mWindowManager.addView(mView, mParams);
// 隐藏
mWindowManager.removeView(mView);
WindowManager.LayoutParams参数细节,具体看源码 -_-!!!也可以看这儿
一个简单的效果:悬浮在整个系统之上,同时能够随着手指移动Window。
/**
* 测试Window
*
* @author fengzhen
* @version v1.0, 2017/7/14
*/
public class TestWindow {
private Context mContext;
private final WindowManager mWindowManager;
private View mView;
private boolean isShowing = false;
private WindowManager.LayoutParams mParams;
public TestWindow(Context context) {
this.mContext = context;
// 根据 WINDOW_SERVICE 获取到 WindowManager
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
}
/**
* 创建布局参数
*
* @author fengzhen
* @version v1.0, 2017/7/14 17:05
*/
private WindowManager.LayoutParams createWindowParams() {
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
// 设置为始终顶层
layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
// 设置弹出的Window不持有焦点
layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
// 大小
layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
// 位置
layoutParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
// 设置背景透明
layoutParams.format = PixelFormat.TRANSLUCENT;
return layoutParams;
}
/**
* 展示弹框
*
* @author fengzhen
* @version v1.0, 2017/7/14 17:14
*/
public void show() {
if (isShowing) return;
if (mView == null) {
mView = LayoutInflater.from(mContext).inflate(R.layout.window_test, null);
//如果需要拖动取消下面注释
mView.findViewById(R.id.btn_hide).setOnTouchListener(new View.OnTouchListener() {
int startX;
int startY;
int startDownX;
int startDownY;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: // 按下
// 手指按下时的坐标位置
startX = (int) event.getRawX();
startY = (int) event.getRawY();
startDownX = (int) event.getRawX();
startDownY = (int) event.getRawY();
break;
case MotionEvent.ACTION_MOVE: // 移动
// 移动后的坐标位置
int newX = (int) event.getRawX();
int newY = (int) event.getRawY();
// 偏移量
int dx = newX - startX;
int dy = newY - startY;
// 给偏移量设置边距
// 小于x轴
if (mParams.x < 0) {
mParams.x = 0;
}
// 小于y轴
if (mParams.y < 0) {
mParams.y = 0;
}
// 超出x轴
if (mParams.x > mWindowManager.getDefaultDisplay().getWidth() - mView.getWidth()) {
mParams.x = mWindowManager.getDefaultDisplay().getWidth() - mView.getWidth();
}
// 超出y轴
if (mParams.y > mWindowManager.getDefaultDisplay().getHeight() - mView.getHeight()) {
mParams.y = mWindowManager.getDefaultDisplay().getHeight() - mView.getHeight();
}
// 更新窗体的坐标
mParams.x += dx;
mParams.y += dy;
mWindowManager.updateViewLayout(mView, mParams);
// 重新赋值起始坐标
startX = (int) event.getRawX();
startY = (int) event.getRawY();
break;
case MotionEvent.ACTION_UP: // 抬起
int upX = (int) event.getRawX();
int upY = (int) event.getRawY();
// 更新窗体的坐标
if (upX < mWindowManager.getDefaultDisplay().getWidth() / 2) {
for (int i = 0; i < mWindowManager.getDefaultDisplay().getWidth() / 2; i++) {
mParams.x = upX - i;
mWindowManager.updateViewLayout(mView, mParams);
}
} else {
for (int i = 0; i < mWindowManager.getDefaultDisplay().getWidth() / 2; i++) {
mParams.x = upX + i;
mWindowManager.updateViewLayout(mView, mParams);
}
mParams.x = mWindowManager.getDefaultDisplay().getHeight();
}
break;
default:
break;
}
return true; // 当有父控件有点击事件时,这里要返回false,不然父控件就拿不到点击事件了
}
});
mParams = createWindowParams();
}
mWindowManager.addView(mView, mParams);
isShowing = true;
}
/**
* 隐藏
*
* @author fengzhen
* @version v1.0, 2017/7/14 17:14
*/
public void hide() {
if (!isShowing) return;
if (mWindowManager != null && mView != null) {
mWindowManager.removeView(mView);
isShowing = false;
}
}
}