[Android]PopupWindow 点击外部区域无法关闭的问题

[TOC]
在android4.0/5.0系统上,使用popupWindow时,点击内容外部区域无法关闭,但是在6.0机子上又是正常的,而我在代码中明明已经进行了如下设置:

mPopupWindow = new PopupWindow(popView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);
// 点击其他地方消失
mPopupWindow.setOutsideTouchable(true);

点击外部区域不关闭

红色区域是popupwindow内容区域

google了一下都说要添加一句:

mPopupWindow.setBackgroundDrawable(new BitmapDrawable());

测试了果然ok,不过还是想知道下所以然,稍微探究一下:
既然是点击没效果,搜索一下touch事件好了:
在4.0/5.0的 PopupWindow.java 源码中发现是在 PopupViewContainer 类中设置的,而在6.0源码中则是位于 PopupDecorView 类;

继续查找在哪里初始化的,发现 preparePopup(),它是在显示(showAtLocation() , showAsDropDown())的时候调用的,而 preparePopup() 的具体内容:

// PopupWindow.java @ api 14/19/21
private void preparePopup(WindowManager.LayoutParams p) {
    if (mContentView == null || mContext == null || mWindowManager == null) {
        throw new IllegalStateException("You must specify a valid content view by "
                + "calling setContentView() before attempting to show the popup.");
    }

    if (mBackground != null) {
        final ViewGroup.LayoutParams layoutParams = mContentView.getLayoutParams();
        int height = ViewGroup.LayoutParams.MATCH_PARENT;
        if (layoutParams != null &&
                layoutParams.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
            height = ViewGroup.LayoutParams.WRAP_CONTENT;
        }

        // when a background is available, we embed the content view
        // within another view that owns the background drawable
        PopupViewContainer popupViewContainer = new PopupViewContainer(mContext);
        PopupViewContainer.LayoutParams listParams = new PopupViewContainer.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT, height
        );
        popupViewContainer.setBackgroundDrawable(mBackground);
        popupViewContainer.addView(mContentView, listParams);

        mPopupView = popupViewContainer;
    } else {
        mPopupView = mContentView;
    }
    mPopupWidth = p.width;
    mPopupHeight = p.height;
}

这里可以看到当background不为null的时候,在contentView外面套了一层PopupViewContainer,而PopupViewContainer中才有关于touch,key的监听事件,因此若未设置背景,则点击外部区域无法取消popupwindow,即使设置了:

mPopupWindow.setOutsideTouchable(true);

而在android6.0中:

// PopupWindow.java @ api 23
private void preparePopup(WindowManager.LayoutParams p) {
    ......

    // When a background is available, we embed the content view within
    // another view that owns the background drawable.
    if (mBackground != null) {
        mBackgroundView = createBackgroundView(mContentView);
        mBackgroundView.setBackground(mBackground);
    } else {
        mBackgroundView = mContentView;
    }

    // 无论background是否为空,都会创建decorView,它是PopupDecorView的实例,其实就是一个FrameLayout,里面有touch事件的监听,因此无需设置背景也可以点击外部区域取消popupwindow的
    mDecorView = createDecorView(mBackgroundView);
    ......
}

总之,跟网友说的一致,添加背景图片就可以了:

Bitmap bmp = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.bg_popup_window);
Drawable drawable = new BitmapDrawable(getContext().getResources(), bmp);
// 不带参的方法已经deprecated
popupWindow.setBackgroundDrawable(drawable);
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android中,如果你想要点击PopupWindow周围关闭弹窗,可以通过以下几个步骤实现: 1.创建一个透明的背景层,并添加点击事件,当用户点击背景层时,关闭PopupWindow。 2.在PopupWindow的showAsDropDown()方法中,设置setBackgroundDrawable(),将PopupWindow的背景设置为透明,这样点击背景层时,点击事件才能被响应。 下面是示例代码: ```java // 创建透明的背景层 View backgroundView = new View(context); backgroundView.setBackgroundColor(Color.parseColor("#80000000")); backgroundView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { popupWindow.dismiss(); } }); // 创建PopupWindow View contentView = LayoutInflater.from(context).inflate(R.layout.popup_layout, null); PopupWindow popupWindow = new PopupWindow(contentView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); popupWindow.setFocusable(true); // 设置PopupWindow可以获取焦点 popupWindow.setOutsideTouchable(true); // 设置PopupWindow外部点击 popupWindow.showAsDropDown(anchorView); // 添加背景层 ViewGroup rootView = (ViewGroup) ((Activity) context).getWindow().getDecorView().findViewById(android.R.id.content); rootView.addView(backgroundView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); ``` 这样,当用户点击PopupWindow周围的背景层时,就可以关闭弹窗了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值