Android悬浮窗使用及窗口设置相关

显示一个悬浮窗,窗口类型设置,获取状态栏高度

1、显示一个悬浮窗
首先通过 getSystemService(Context.WINDOW_SERVICE) 拿到 WindowManager , 然后向其中 addView addView 第二个参数是一个 WindowManager.LayoutParams WindowManager.LayoutParams 中有一个成员 type , 有各种值, 一般设置成 TYPE_PHONE 就可以悬浮在很多view的上方了, 但是调用这个方法需要申请 android.permission.SYSTEM_ALERT_WINDOW 权限。

例子:
public class WindowSmallView extends RelativeLayout {
//先写一个类继承布局类型,在这个类里面实现操作
    public WindowSmallView(Context context) {
	WindowManager mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
	//拿到WindowManager
	View mWindowView = LayoutInflater.from(context).inflate(R.layout.window_small, this);
	//将对应RelativeLayout布局填充进来,该布局是自定义的
	addView();
    }
}


添加该悬浮窗view到窗口显示:

private void addView() {
    WindowManager.LayoutParams mLayoutParams = new WindowManager.LayoutParams();
    mLayoutParams.type = WindowManager.LayoutParams.TYPE_TOAST;//TYPE_SYSTEM_OVERLAY 比 TYPE_PHONE 更高级,可以避免应用程序改变状态栏时被覆盖,但是不能点击滑动
    mLayoutParams.format = PixelFormat.RGBA_8888;
    mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL // 不阻塞事件传递到后面的窗口
            //| WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION
            | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE // 悬浮窗口较小时,后面的应用图标由不可长按变为可长按,弹出的View收不到Back键的事件
                    | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; //不受手机界面限制,比如y值设置为负的时候可以在状态栏上显示

    mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
    mLayoutParams.width = mBoxViewWidth;
    mLayoutParams.height = mBoxViewHeight;//这里设置view的实际高度,这时mBoxViewHeight要比view布局里面设置的height要小,所以布局里面height最好设为match_parent
    mLayoutParams.x = mBoxInScreenX;
    mLayoutParams.y = mBoxInScreenY - mStatusBarHeight;//mScreenHeight/2;//-mStatusBarHeight;

    mWindowView .setLayoutParams(mLayoutParams);
	mWindowManager.addView(mSpeedBoxView, mLayoutParams);
 }

最后只要 new WindowSmallView()即可显示。

 
  
2、窗口类型window type,设置mLayoutParams.type
WindowManager.LayoutParams.TYPE_PHONE:这是非应用窗口,提供与电话的用户交互(特别是来电)。 这些窗口通常放置在所有应用程序之上,但在状态栏后面,会被状态栏显示给覆盖,其他应用全屏时也会覆盖掉。放到状态栏区域显示时,它的点击、触摸事件会被状态栏拦截。锁屏时不显示,在多用户系统中显示在所有用户的窗口。需要android.permission.SYSTEM_ALERT_WINDOW权限。
 
  
WindowManager.LayoutParams.TYPE_TOAST:可以显示在几乎所有界面之上,包括状态栏、锁屏,除了锁屏,其他情况都可以响应点击触摸事件。在多用户系统中,只显示拥有用户的窗口。API level 19 以下因无法接收无法接收触摸(点击)和按键事件。不需要android.permission.SYSTEM_ALERT_WINDOW权限也可显示,但vivo x9 6.0系统测试需要。测试Huawei mate9、6P 7.0系统时该TYPE在状态栏区域不响应触摸事件,也不能覆盖锁屏,但不需要android.permission.SYSTEM_ALERT_WINDOW权限。OPPO R9 5.1系统测试状态栏显示会被一些应用draw状态栏时所覆盖,vivo 5.1则不会,这两个都不需要android.permission.SYSTEM_ALERT_WINDOW权限即可显示。
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:系统窗口,如低功率警报。 这些窗口总是在应用程序窗口的顶部。和TYPE_PHONE类似,除了状态栏位置,可以显示在其他任何应用界面之上,其他应用全屏时也不会覆盖它。 在多用户系统中,只显示拥有用户的窗口。需要android.permission.SYSTEM_ALERT_WINDOW权限。
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:系统覆盖窗口,需要显示在其他所有窗口之上。 这些窗口不能采取输入焦点,否则会干扰键盘锁。 因此不能响应点击、触摸事件。在多用户系统中,只显示拥有用户的窗口。如果不需要响应点击、触摸事件,这个是最好的,能覆盖所有界面之上。
WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:internal system error windows, appear on top of everything they can. In multiuser systems shows only on the owning user's window. 这个可以显示所有界面之上包括锁屏等,除了状态栏不能覆盖。
WindowManager.LayoutParams.TYPE_APPLICATION: 只能配合Activity在当前APP使用TYPE_APPLICATION_ATTACHED_DIALOG: 只能配合Activity在当前APP使用
3、获取状态栏高度:
private int getStatusBarHeight() {
    int statusBarHeight = 0;
    if (statusBarHeight == 0) {
        try {
            Class<?> c = Class.forName("com.android.internal.R$dimen");
            Object o = c.newInstance();
            Field field = c.getField("status_bar_height");
            int x = (Integer) field.get(o);
            statusBarHeight = getResources().getDimensionPixelSize(x);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    return statusBarHeight;
}


addView();

猜你喜欢

转载自blog.csdn.net/forLittleBlue/article/details/59563755
今日推荐