安卓UIIT之家

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详解

上一篇 下一篇

猜你喜欢

热点阅读