android PopupWindow关于返回按键的判断

1、首先讲解下业务需求,在一个activity中弹出PopupWindow,要求点击外部区域pop不消失,并且点击返回按键pop消失并且需要关闭当前activity。
第一步:点击外部区域不消失
第一想法是setOutsideTouchable(false); // 设置popupwindow外部可点击
然后并没有达到我想要的效果
最终的设置包括popupWindow的软键盘在内

    //此popup需要软键盘
    this.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
    //软键盘弹出时不会覆盖popuwindow
    this.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
    this.setTouchable(true); // 设置popupwindow可点击
    this.setOutsideTouchable(false); // 设置popupwindow外部可点击
    this.setFocusable(true); // 获取焦点

后来看了很多博客发现好像都一样,说什么设置背景 就能生成一个 跟布局给你写了N多代码

接下来分析一下源码吧 因为自己也找不到问题在哪里!
步骤1、

public void setBackgroundDrawable(Drawable background) {
    mBackground = background;
}

我删了部分代码,关键是mBackground;

步骤2、

private void preparePopup(WindowManager.LayoutParams p) {
    if (mDecorView != null) {
        mDecorView.cancelTransitions();
    }
    if (mBackground != null) {
        mBackgroundView = createBackgroundView(mContentView);
        mBackgroundView.setBackground(mBackground);
    } else {
        mBackgroundView = mContentView;
    }

    ***mDecorView = createDecorView(mBackgroundView);***
}
我删掉了部分代码自己可以去popupWindow去看源码 反正网上讲的设置mBackground目前已经过时了吧,因为不管设置没有肯定跟布局是createDecorView(mBackgroundView)生成的

步骤3、

private PopupDecorView createDecorView(View contentView) {
        final ViewGroup.LayoutParams layoutParams = mContentView.getLayoutParams();
        final int height;
        if (layoutParams != null && layoutParams.height == WRAP_CONTENT) {
            height = WRAP_CONTENT;
        } else {
            height = MATCH_PARENT;
        }

        final PopupDecorView decorView = new PopupDecorView(mContext);
        decorView.addView(contentView, MATCH_PARENT, height);
        decorView.setClipChildren(false);
        decorView.setClipToPadding(false);

        return decorView;
    }

生成一个PopupDecorView作为根布局

步骤4、看看这个类咯 PopupDecorView

private class PopupDecorView extends FrameLayout {
        private TransitionListenerAdapter mPendingExitListener;

        public PopupDecorView(Context context) {
            super(context);
        }

        @Override
        public boolean dispatchKeyEvent(KeyEvent event) {
            if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
                if (getKeyDispatcherState() == null) {
                    return super.dispatchKeyEvent(event);
                }

                if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
                    final KeyEvent.DispatcherState state = getKeyDispatcherState();
                    if (state != null) {
                        state.startTracking(event, this);
                    }
                    return true;
                } else if (event.getAction() == KeyEvent.ACTION_UP) {
                    final KeyEvent.DispatcherState state = getKeyDispatcherState();
                    if (state != null && state.isTracking(event) && !event.isCanceled()) {
                        dismiss();
                        return true;
                    }
                }
                return super.dispatchKeyEvent(event);
            } else {
                return super.dispatchKeyEvent(event);
            }
        }

        @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
            if (mTouchInterceptor != null && mTouchInterceptor.onTouch(this, ev)) {
                return true;
            }
            return super.dispatchTouchEvent(ev);
        }

        @Override
        public boolean onTouchEvent(MotionEvent event) {
            final int x = (int) event.getX();
            final int y = (int) event.getY();

            if ((event.getAction() == MotionEvent.ACTION_DOWN)
                    && ((x < 0) || (x >= getWidth()) || (y < 0) || (y >= getHeight()))) {
                dismiss();
                return true;
            } else if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
                dismiss();
                return true;
            } else {
                return super.onTouchEvent(event);
            }
        }

然后跟布局一个FrameLayout 里面按键分发把物理返回键写死了。
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK)
} else if (event.getAction() == KeyEvent.ACTION_UP) {
dismiss();
这样下来大概逻辑 物理返回键 松开我给你关了这个popupWindow
天呐!!!为什么会这样 那不是返回按键我永远也获取不到了么
绝望ing
我提出的第二个问题已经看到结局了 就是物理返回键别人帮你做掉了,控件dismiss

那我们来看看第一个问题: 点击外部控件不消失 很显然这是一个TouchEvent

看看onTouchEvent发现 他又干了一些事情

if ((event.getAction() == MotionEvent.ACTION_DOWN)
&& ((x < 0) || (x >= getWidth()) || (y < 0) || (y >= getHeight()))) {
dismiss();
return true;
} else if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
dismiss();
return true;
}
解析一下就是 超出 控件大小范围的事件 我会把控件给消失掉。
但是虽然这么写了还是有救命的方法的 dispatchTouchEvent()方法有一个接口mTouchInterceptor

机智的我立马 写了 this就是自己的自定义popup

    private void addTouchListener(){
        this.setTouchInterceptor(new View.OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                final int x = (int) event.getX();
                final int y = (int) event.getY();
                if ((event.getAction() == MotionEvent.ACTION_DOWN) && ((y < 0) || (y >= getHeight()))) {
                    return true;
                } else if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
                    return true;
                }
                return  false;
            }
        });
    }

问题1点击外部区域不消失迎刃而解 这里有个坑,你定义Pop宽高有match_parent或者wrap_content的时候拿出来的的实际高度有可能是-1 -2 的枚举值 反正我一路被坑过来,我这边设置的话宽度match_prarent 高度自己定义的
所以写 setTouchInterceptor的时候只判断高度就OK

写了这么多问题2 困扰我很久有想过PopupWindow自己写一个或者添加什么onKeyListener 都不行 然后很绝望 最后都想用Dialog来实现了 反正浪费了很多时间

最后问了大神 怎么解决这个问题 大神说你加个标志位 判断一下不就行了 然后我就解决了问题2。

反正都是消失连带关闭activity 那我就一个正常消失不关闭的途径,添加个标志位 完美解决,

反正最后是哭了,一大波弯路和坑 写了一堆有的没的 ,结果干不过经验老道的大神的一个标志位

写的是有点乱。 记录一下 下次用的话给自己提个醒

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
嗨!对于你关于 Android PopupWindow 的问题,我可以给你一些基本的信息。PopupWindowAndroid 中的一个弹出式窗口,它可以覆盖在其他视图之上,提供一种临时性的用户界面。你可以使用 PopupWindow 来显示额外的内容、菜单或者交互提示。 要创建一个 PopupWindow,首先你需要实例化一个 PopupWindow 对象,并为其设置一些基本属性,例如宽度、高度、背景等。然后,你可以将任何视图或布局添加到 PopupWindow 中,并通过设置位置参数来控制它的显示位置。 下面是一个简单的示例代码,展示如何创建和显示一个 PopupWindow: ```java // 创建一个 PopupWindow 对象 PopupWindow popupWindow = new PopupWindow(context); // 设置 PopupWindow 的宽度和高度 popupWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT); popupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT); // 设置 PopupWindow 的内容视图 View contentView = LayoutInflater.from(context).inflate(R.layout.popup_layout, null); popupWindow.setContentView(contentView); // 设置 PopupWindow 的背景 popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); // 显示 PopupWindow popupWindow.showAtLocation(anchorView, Gravity.CENTER, 0, 0); ``` 在上面的示例中,我们创建了一个 PopupWindow 对象,并设置了宽度和高度为包裹内容。然后,我们通过调用 `setContentView` 方法将一个自定义的布局文件 `R.layout.popup_layout` 添加到 PopupWindow 中。最后,我们使用 `showAtLocation` 方法将 PopupWindow 显示在屏幕中央。 希望这些信息对你有帮助!如果你对 PopupWindow 有更多的问题,或者需要更详细的示例代码,请随时告诉我。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值