WindowManager addView弹窗功能

touch here
android在WindowManager添加View
作者:feiyangxiaomi

1. 事情的起因

项目的驱动,希望提供一个弹窗,这个弹窗的特点是:
- 非阻塞试弹窗,弹窗弹出的时候,点击弹窗外的屏幕区域,–不选PopupWindow(开源项目QuickAction不能用)
- 弹窗需要内部能够点击某一项并做出相应,–不选Toast

此时考虑在界面上加入一个View,通过WindowManager.addView方法去添加弹出图层,这里先贴出一个图,看一下这个效果是否是你的菜:
//截图
效果

2. 为什么选择WindowManager.addView

WindowManager用来在应用与window之间的管理接口,管理窗口顺序,消息等。对于windowManager来说一个系统只有一个,它是由系统底层实现的,用于负责调度当前显示那个窗口,消息处理我们获得一个windowManager的方式如下:

WindowManager windowManager = (WindowManager)context().getSystemService(Context.WINDOW_SERVICE);

调用比较简单。

3.代码实现

把这个弹窗叫做PopupAction,后面统一为这个称呼。

显示PopupAction代码

    /**
     * Show quick menu popup. Popup is automatically positioned, on top of anchor view. Calc of anchor and mRootView
     * view for look out the poosition. Every side margin of 10dp and the arrow at the top of anchor.
     * 
     * @param context the global information about an applicaion environment
     * @param anchor view of call for
     * @param actions action list items {@link #addActionItem(List)}
     */
    public void show(Context context, View anchor, List<ActionItem> actions) {
        mContext = context;
        if (mContext == null) {
            Log.i("MenuDialog", "context is null");
            return;
        }
        int xPos;
        int yPos;
        int arrowPos;
        int[] location = new int[2];

        //添加菜单项
        addActionItem(actions);

        mShowAction = true;
        //计算要弹出的位置
        anchor.getLocationOnScreen(location);
        Rect anchorRect =
                new Rect(location[0], location[1], location[0] + anchor.getWidth(), location[1] + anchor.getHeight());

        int rootHeight = mRootView.getMeasuredHeight();
        int rootWidth = mRootView.getMeasuredWidth();

        xPos = anchorRect.centerX() - (rootWidth / 2);

        //对弹窗靠近左边和右边的处理
        if (xPos < 20) {
            xPos = 20;
        }
        DisplayMetrics dm = mContext.getResources().getDisplayMetrics();
        if ((dm.widthPixels - anchorRect.centerX()) < rootWidth / 2) {
            xPos = dm.widthPixels - rootWidth - 20;
        }
        arrowPos = anchorRect.centerX() - xPos;
        yPos = anchorRect.top - rootHeight;

        //设置箭头位置
        showArrow((R.id.arrow_down), arrowPos);

        //添加图层弹窗
        android.view.WindowManager.LayoutParams params =
                (android.view.WindowManager.LayoutParams) mRootView.getLayoutParams();

        params.x = xPos;
        params.y = yPos;
        mWM.addView(mParentView, params);
        mParentView.addView(mRootView);
        mParentView.setOnTouchListener(this);

        //设置弹出动画
        Animation animationUp = AnimationUtils.loadAnimation(mContext, R.anim.grow_from_bottom);
        mRootView.startAnimation(animationUp);
    }

其中初始化View,添加菜单项和设置点击菜单项的点击回调,参考QuickAction的代码,这里不再介绍。

4.本文的目标点

WindowManager和WindowManager.LayoutParams

  1. 添加的view不显示,引出WindowManager.LayoutParams用什么type?
  2. 属性WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,如何响应点击outside和back键盘?可以看下stackoverflow很有意思
  3. 属性WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY能不能用?
    对于WindowManager.LayoutParams配置代码:
    mParams = new WindowManager.LayoutParams();
    mParams.height = LayoutParams.WRAP_CONTENT;
    mParams.width = LayoutParams.WRAP_CONTENT;
    mParams.format = PixelFormat.TRANSLUCENT;
    mParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
    mParams.flags =
            WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
    mParams.gravity = Gravity.TOP | Gravity.LEFT;
    mRootView.setLayoutParams(mParams);

可以看到这里使用的type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;,后面介绍一下几种类型。
flag使用
- LayoutParams.FLAG_NOT_TOUCH_MODAL表示可以点击弹窗之外的屏幕区域,这是必须的。
- LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH表示可以监听外部点击事件,这时候可以dismiss掉当前的弹窗,也是必需的。
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 表示当前弹窗捕获得焦点,但能点击,非常重要。不然键盘区域的所有touch事件都会收不到。

Constants
TYPE_ACCESSIBILITY_OVERLAY窗口重叠仅由AccessibilityService截取用户交互,而不改变窗口的无障碍服务可以内省。
TYPE_APPLICATION应用窗口
TYPE_APPLICATION_ATTACHED_DIALOG和TYPE_APPLICATION_PANEL类似,但是不作为一个应用的一部分,显示在窗口的顶层
TYPE_APPLICATION_PANEL应用顶层图层
TYPE_APPLICATION_MEDIA播放器图层
TYPE_APPLICATION_STARTING应用开始事的图层
TYPE_APPLICATION_SUB_PANEL应用子面板
TYPE_PHONE电话图层,部分手机无法使用,已测试
~
TYPE_SYSTEM_ALERT系统通知,使用时发现该图层会独立在应用之上
TYPE_SYSTEM_DIALOG系统对话框,使用时发现该图层会独立在应用之上
TYPE_SYSTEM_ERROR系统错误,非常靠上
TYPE_SYSTEM_OVERLAY系统普通图层
TYPE_TOAST系统toast

参考网上实例的时候,建议不要采用系统图层,网上的好多实例都是采用:TYPE_SYSTEM_ALERT,不合理。

WindowManager.addView的动画效果

动画部分可以采用:
WindowManager.windowAnimations=R.style.xxx但是不建议使用,该资源在官网上说是鼻息使用系统资源,因为window manager拿到应用的资源。
那怎么办?参考:WindowManager with Animation (is it possible?)
代码如下所示:

    mParentView = new FrameLayout(mContext);
    mWM.addView(mParentView, params);
    mParentView.addView(mRootView);
    Animation animationUp = AnimationUtils.loadAnimation(mContext, R.anim.grow_from_bottom);
    mRootView.startAnimation(animationUp);

借助于ViewGroup(定义的mParentView),使用动画效果,小技巧很不错。

参考

  1. QuickAction
  2. WindowManager with Animation (is it possible?)
  3. 官方文档
  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
安卓全局弹窗窗口是指可以在应用程序的任何界面上显示的弹窗窗口。在安卓上,可以通过使用系统的WindowManager来实现全局弹窗窗口。 要创建一个全局弹窗窗口,你需要遵循以下步骤: 1. 在你的应用程序的AndroidManifest.xml文件中,添加以下权限: ```xml <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> ``` 这是为了允许你的应用程序在其他应用程序的顶部显示窗口。 2. 在你的应用程序中,创建一个新的Window对象,并设置其参数和属性: ```java WindowManager.LayoutParams params = new WindowManager.LayoutParams( WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN, PixelFormat.TRANSLUCENT); params.gravity = Gravity.TOP | Gravity.START; params.x = 0; params.y = 0; params.width = WindowManager.LayoutParams.MATCH_PARENT; params.height = WindowManager.LayoutParams.WRAP_CONTENT; ``` 这个示例代码创建了一个全屏宽度,自适应高度的窗口,并将其设置为位于屏幕顶部。 3. 使用WindowManageraddView()方法将窗口添加到窗口管理器中: ```java WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE); windowManager.addView(yourView, params); ``` 这将在窗口管理器中添加你的自定义视图(yourView)。 请注意,全局弹窗窗口需要特殊权限,并且在Android 8.0及更高版本中,需要应用程序具有SYSTEM_ALERT_WINDOW权限。此外,全局弹窗窗口的使用也可能会受到一些限制和限制,以确保用户体验和安全性。 希望这可以帮助你创建安卓全局弹窗窗口!如果你有任何其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值