安卓悬浮窗两种实现与踩坑

第一种 需要权限的悬浮窗:

权限:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

禁用事件:

layoutParams.flags =
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;

不禁用事件:

//不影响悬浮覆盖的view所以事件,单纯的是个盖板,就像护眼宝一样
layoutParams.flags =
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE |
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;

全屏设置:

layoutParams.flags =
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
 //屏幕不限制   高度layoutParams.height = 5000超过手机屏幕高度都可
layoutParams.height = WindowManager.LayoutParams.MATCH_PARENT+5000;

不全屏(状态栏不会被覆盖):

layoutParams.flags =
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
 //屏幕不限制   高度layoutParams.height = 5000超过手机屏幕高度都可
layoutParams.height = WindowManager.LayoutParams.MATCH_PARENT;

组合 1 全屏,不禁用事件:

效果:不影响手机滑动以及任何操作

        layoutParams.flags =
                //不影响悬浮覆盖的view所以事件,单纯的是个盖板,就像护眼宝一样
                WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE |
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |

                //屏幕不限制   高度layoutParams.height = 5000超过手机屏幕高度都可
                WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;


        layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
//屏幕不限制   高度layoutParams.height = 5000超过手机屏幕高度都可
        layoutParams.height = WindowManager.LayoutParams.MATCH_PARENT+5000;

代码:

package com.hlz.mytools;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.os.Build;
import android.provider.Settings;
import android.view.Gravity;
import android.view.View;
import android.view.WindowManager;

import static android.content.Context.WINDOW_SERVICE;


public class FloatWindowManager {
    private volatile static FloatWindowManager instance = null;
    private Activity mAct;
    private WindowManager windowManager;
    private WindowManager.LayoutParams layoutParams;
    private View view;


    private FloatWindowManager(Activity activity) {
        this.mAct = activity;
        init(mAct);
    }

    private void init(Activity activity) {
        windowManager = (WindowManager) activity.getSystemService(WINDOW_SERVICE);
        layoutParams = new WindowManager.LayoutParams();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        } else {
//            layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
            layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        }
        layoutParams.format = PixelFormat.RGBA_8888;
        layoutParams.gravity = Gravity.CENTER;
        layoutParams.alpha = 0.5f;
//        layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        layoutParams.flags =
                //不影响悬浮覆盖的view所以事件,单纯的是个盖板,就像护眼宝一样
                WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE |
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |

                //屏幕不限制   高度layoutParams.height = 5000超过手机屏幕高度都可
                WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;

//        WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
//                WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
//                WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH |
//
//                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
//                        WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;

        layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
        layoutParams.height = WindowManager.LayoutParams.MATCH_PARENT+5000;
    }

    public static FloatWindowManager getInstance(Activity mAct) {
        if (instance == null) {
            synchronized (FloatWindowManager.class) {
                if (instance == null) {
                    instance = new FloatWindowManager(mAct);
                }
            }
        }
        return instance;

    }



    @SuppressLint("NewApi")
    public void showFloatingWindow() {
        if (Settings.canDrawOverlays(mAct)) {
            view = new View(mAct.getApplicationContext());
            view.setBackgroundColor(Color.BLACK);
            windowManager.addView(view, layoutParams);
        }
    }

    public void hideFloatingWindow() {
        if (null != view && windowManager != null) {
            windowManager.removeViewImmediate(view);
        }

    }
}

第二种 不需要权限悬浮:

用kotlin实现代码:

package com.bjx.bjxcommon.view

import android.annotation.SuppressLint
import android.app.Activity
import android.app.Application
import android.graphics.Color
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import java.lang.ref.WeakReference


class FloatViewManager constructor(activity: Activity, val isOpen: Boolean = false) {
    private var view: View? = null
    private var isFirstInit = true
    private val context by lazy { WeakReference(activity).get() }

    init {
        if (isOpen) {
            init()
        }
    }

    @SuppressLint("NewApi")
    fun init() {
        if (!isFirstInit) return
        isFirstInit = false
        context?.registerActivityLifecycleCallbacks(object :
            Application.ActivityLifecycleCallbacks {

            override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {

            }


            override fun onActivityStarted(activity: Activity) {

            }


            override fun onActivityResumed(activity: Activity) {
                addView()
            }


            override fun onActivityPaused(activity: Activity) {

            }


            override fun onActivityStopped(activity: Activity) {

            }


            override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {

            }


            override fun onActivityDestroyed(activity: Activity) {
                view?.let {
                    removeView(it)
                }
                view = null
                context?.unregisterActivityLifecycleCallbacks(this)
            }
        })
    }

    fun update() {

    }

    fun addView() {
        if (isAdd()) return
        context?.let { context ->
            view = View(context)
            view?.let {
                it.setBackgroundColor(Color.BLACK)
                it.alpha = 0.4f
                val vg = context.window.decorView
                when (vg) {
                    is ViewGroup -> {
                        vg.addView(
                            it,
                            ViewGroup.LayoutParams(
                                ViewGroup.LayoutParams.MATCH_PARENT,
                                ViewGroup.LayoutParams.MATCH_PARENT
                            )
                        )
                    }
                }
            }
        }

    }

    fun removeView(view: View) {
        context?.let {
            val vg = it.window.decorView
            when (vg) {
                is ViewGroup -> {
                    if (isAdd()) {
                        vg.removeView(view)
                    }
                }
            }
        }
    }

    fun isAdd(): Boolean {
        if (context == null) return false
        val vg = context!!.window.decorView
        when (vg) {
            is ViewGroup -> {
                if (vg.childCount > 0) {
                    for (i in 0..vg.childCount - 1) {
                        val v = vg.getChildAt(i)
                        if (v == view) {
                            return true
                        }
                    }
                }
            }
        }
        return false
    }
}

在BaseActivity中调用:

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

//FloatViewManager 内部会自动注销回收,无需在Activity中释放了
        FloatViewManager(this,true)
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值