Android 悬浮窗整理
2019-03-01 本文已影响274人
光羽隼
先上代码吧:https://github.com/gys0000/FloatView
我这里边只是整理了悬浮窗的显示和拖拽,因为悬浮窗是一个容器,你可以往里边添加各种控件。比如视频等等。。。
这个悬浮窗是我接手别人的项目,上一位同事封装的一个悬浮窗的基类,很好用。
要创建悬浮窗需要动态申请一下权限,因为我的项目是有系统权限的,所以没太关注这方面。demo中简单加了动态权限申请。
首先看一下基类 FloatView
public abstract class FloatView {
private final WindowManager mWindowManager;
private Context mContext;
private WindowManager.LayoutParams mParams;
private boolean isShowing = false;
private boolean mCreate = false;
private View mDecor;
private boolean isCanMove = false;
public FloatView(@NonNull Context context) {
mContext = context;
//窗口管理器
mWindowManager = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE));
//布局参数
mParams = new WindowManager.LayoutParams();
mParams.type = WindowManager.LayoutParams.TYPE_PHONE;
// mParams.type = WindowManager.LayoutParams.TYPE_PHONE;
// mParams.type = WindowManager.LayoutParams.TYPE_SEARCH_BAR;
// mParams.type = WindowManager.LayoutParams.TYPE_INPUT_METHOD;
mParams.format = PixelFormat.RGBA_8888;
//设置之后window永远不会获取焦点,所以用户不能给此window发送点击事件焦点会传递给在其下面的可获取焦点的window
mParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
//WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; //设置之后window永远不会获取焦点,所以用户不能给此window发送点击事件焦点会传递给在其下面的可获取焦点的windo
//WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
//WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |//当这个window对用户是可见状态,则保持设备屏幕不关闭且不变暗
// WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS |//允许window扩展值屏幕之外
//WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;//当window被添加或者显示,系统会点亮屏幕,就好像用户唤醒屏幕一样*/
mParams.gravity = Gravity.LEFT | Gravity.TOP;
mParams.width = setWidth();
mParams.height = setHeight();
if (setCreateAnimator() != 0) {
//出现的动画
mParams.windowAnimations = setCreateAnimator();
}
}
//设置布局文件
protected abstract Object setContentView();
//子类实现,设置宽高
protected abstract int setHeight();
protected abstract int setWidth();
......
//显示悬浮窗
public void show() {
if (isShowing) {
if (mDecor != null) {
mDecor.setVisibility(View.VISIBLE);
}
return;
}
if (!mCreate) {
create();
mCreate = true;
}
mWindowManager.addView(mDecor, mParams);
isShowing = true;
onStart();
}
private void create() {
mDecor = LayoutInflater.from(getContext()).inflate((Integer) setContentView(), null);
onCreate(mDecor, mParams);
if (isCanMove) {
mDecor.setOnTouchListener(new FloatOnTouchListener());
}
//如果集成的有ButterKnife,可以在这里声明ButterKnife.bind(this, mDecor);
}
//隐藏悬浮窗
public void dismiss() {
if (mDecor == null || !isShowing) {
return;
}
try {
onStop();
mWindowManager.removeViewImmediate(mDecor);
//这个地方可以注销ButterKnife
} finally {
mDecor = null;
isShowing = false;
mCreate = false;
//这里可以还原参数
}
}
.....
}
上边是稍微简略的代码,勉强看看。具体还是看GitHub中的代码。
这里边有两个需要注意的地方,不同版本的系统,WindowManager.LayoutParams.TYPE_PHONE这个参数的使用不同,在Android 8.0之前,悬浮窗口设置可以为TYPE_PHONE,这种类型是用于提供用户交互操作的非应用窗口。 在Android 8.0之后,就要使用其他参数。
还有 mParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;这个参数也是需要注意的,使用不当可能会影响系统按键点击事件的接收不到。上次遇到的问题搞忘了,遇到了我再写上来。
参考:
Android悬浮窗的实现
WindowManager.LayoutParams详解