Android弹出窗口关闭

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3121232/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 08:48:34  来源:igfitidea点击:

Android popup window dismissal

androidpopupwindow

提问by Bostjan

I have a popup window displaying when I click an item in my list activity. The problem is that the back key doesn't close it. I tried catching the back key in my list activity but it doesn't register it...then I tried registering a onkeylistener to the view I'm passing to my popup window. Like this:

单击列表活动中的项目时,会显示一个弹出窗口。问题是后退键不会关闭它。我尝试在我的列表活动中捕获返回键,但它没有注册它......然后我尝试将一个 onkeylistener 注册到我传递给我的弹出窗口的视图中。像这样:

pop.setOnKeyListener(new View.OnKeyListener() {

        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {
            // TODO Auto-generated method stub
            boolean res=false;
            if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
                // do something on back.
                Log.e("keydown","back");
                if (pw.isShowing()) {
                    Log.e("keydown","pw showing");
                    pw.dismiss();
                    res = true;
                }
            } else {
                res = false;
            }
            return res;
        }
    });

which is passed to a popup like this:

它传递给这样的弹出窗口:

pw = new PopupWindow(
       pop, 
       240, 
       70, 
       true);

But that listener doesn't fire neither. Can you help me? I'm out of ideas :)

但是那个监听器也不会触发。你能帮助我吗?我没有想法:)

回答by Rich Schuler

This is because the popup window does not respond to onTouch or onKey events unless it has a background that != null. Check out some code I wroteto help with this. In the basic case you can to call PopupWindow#setBackgroundDrawable(new BitmapDrawable())to force it to act the way you expect. You won't need your own onKey listener. You might also need to call PopupWindow#setOutsideTouchable(true)if you want it to go away when the user clicks outside of the window boundaries.

这是因为弹出窗口不会响应 onTouch 或 onKey 事件,除非它的背景为 != null。查看我编写的一些代码来帮助解决这个问题。在基本情况下,您可以调用PopupWindow#setBackgroundDrawable(new BitmapDrawable())强制它按照您期望的方式行事。您不需要自己的 onKey 侦听器。PopupWindow#setOutsideTouchable(true)如果您希望它在用户单击窗口边界外时消失,您可能还需要调用。

Extended esoteric answer:

扩展深奥的答案:

The reason the background cannot be null is because of what happens in PopupWindow#preparePopup. If it detects background != nullit creates an instance of PopupViewContainerand calls setBackgroundDrawableon that and puts your content view in it. PopupViewContaineris basically a FrameLayoutthat listens for touch events and the KeyEvent.KEYCODE_BACKevent to dismiss the window. If background == null, it doesn't do any of that and just uses your content view. You can, as an alternative to depending on PopupWindowto handle that, extend your root ViewGroupto behave the way you want.

背景不能为空的原因是因为PopupWindow#preparePopup. 如果它检测到background != null它会创建一个实例PopupViewContainer并调用setBackgroundDrawable它并将您的内容视图放入其中。PopupViewContainer基本上是一个FrameLayout监听触摸事件和KeyEvent.KEYCODE_BACK关闭窗口的事件。如果 background == null,它不会执行任何操作,只会使用您的内容视图。作为依赖PopupWindow来处理它的替代方法,您可以扩展您的根ViewGroup以按照您想要的方式行事。

回答by Sunil Parmar

Do as per following it works fine:

按照以下操作它工作正常:

PopupWindow pw;
LayoutInflater inflater = (LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.weight_popup, (ViewGroup)findViewById(R.id.linlay_weight_popup));
pw = new PopupWindow(layout,LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT, true);
pw.setBackgroundDrawable(new BitmapDrawable());
pw.setOutsideTouchable(true);
pw.showAsDropDown(btnSelectWeight);

回答by CoolMind

For new projects it's better to use

对于新项目,最好使用

popupWindow.setBackgroundDrawable(new ColorDrawable());

instead of

代替

popupWindow.setBackgroundDrawable(new BitmapDrawable());

as BitmapDrawable is deprecated. Also, it's better than ShapeDrawable in this case. I noticed that when PopupWindow is a rectangle with rounded corners, ShapeDrawable fills corners with black.

因为 BitmapDrawable 已被弃用。此外,在这种情况下,它比 ShapeDrawable 更好。我注意到当 PopupWindow 是一个带圆角的矩形时,ShapeDrawable 用黑色填充角落。

回答by Vanja

A really simple solution is to write pw.setFocusable(true), but probably you don't want to do this because then the MapActivity won't handle touch events.

一个非常简单的解决方案是编写 pw.setFocusable(true),但您可能不想这样做,因为这样 MapActivity 将无法处理触摸事件。

A better solution is to override the back key, e.g like this:

更好的解决方案是覆盖后退键,例如:

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {

    // Override back button
    if (keyCode == KeyEvent.KEYCODE_BACK) {
        if (pw.isShowing()) {
            pw.dismiss();
            return false;
        }
    }
    return super.onKeyDown(keyCode, event);
} 

Good luck!

祝你好运!

回答by Muhammed Refaat

For the new searchers, as creating a new BitmapDrawableis not allowed now(The constructor BitmapDrawable() is deprecated) , so that you have to change it to a new ShapeDrawable(), so that you will change :

对于新的搜索者,因为new BitmapDrawablenow( The constructor BitmapDrawable() is deprecated)不允许创建 a ,因此您必须将其更改为 a new ShapeDrawable(),以便您将更改:

pw.setBackgroundDrawable(new BitmapDrawable());

To :

到 :

pw.setBackgroundDrawable(new ShapeDrawable());

And the whole work will be like :

整个工作将是这样的:

PopupWindow pw;
LayoutInflater inflater = (LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.weight_popup, (ViewGroup)findViewById(R.id.linlay_weight_popup));
pw = new PopupWindow(layout,LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT, true);
pw.setOutsideTouchable(true);
pw.setBackgroundDrawable(new ShapeDrawable());
pw.setTouchInterceptor(new OnTouchListener() { // or whatever you want
        @Override
        public boolean onTouch(View v, MotionEvent event)
        {
            if(event.getAction() == MotionEvent.ACTION_OUTSIDE) // here I want to close the pw when clicking outside it but at all this is just an example of how it works and you can implement the onTouch() or the onKey() you want
            {
               pw.dismiss();
               return true;
            }
            return false;
        }

});
pw.showAtLocation(layout, Gravity.CENTER, 0, 0);

回答by j2emanue

just use this

就用这个

mPopupWindow.setBackgroundDrawable(new BitmapDrawable(null,""));

which is not deprecated. i'd avoid new ShapeDrawable() as its going to render slowly as it tries to draw a shape when the screen needs to be redrawn.

不推荐使用。我会避免使用 new ShapeDrawable() ,因为它会在需要重绘屏幕时尝试绘制形状时渲染缓慢。

回答by Dwivedi Ji

I hope this will be help for you

我希望这对你有帮助

 pw.setTouchInterceptor(new View.OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            // TODO Auto-generated method stub
            if (event.getAction() == MotionEvent.ACTION_DOWN) {
                pw.dismiss();
            }
            return true;
        }
    });

回答by Carl

you need add setBackgroundDrawable(new BitmapDrawable())for your PopupWindow.

你需要setBackgroundDrawable(new BitmapDrawable())为你的PopupWindow.

回答by guptaatul91

pw.setBackgroundDrawable(new ColorDrawable());  

must wrote it before setContentView

必须在setContentView之前写

This works for me.

这对我有用。

回答by tm1701

Are you looking for the combination of the popupwindow dismiss and a good working of the BACK button, then you may consider the below solution.

您是否正在寻找弹出窗口关闭和BACK 按钮良好工作的组合,那么您可以考虑以下解决方案。

Solution principle: all button clicks near your popup window will be intercepted, but any BACK button will not be intercepted. So, if you have anything in you popupwindow that takes action, then set an indication just before your call to dismiss(). In your setOnDismissListener() perform an extra action (like getActivity().popupBackStack()).

解决原理:弹窗附近的所有按钮点击都会被拦截,但不会拦截任何BACK按钮。因此,如果您的弹出窗口中有任何需要采取行动的内容,请在您调用dismiss() 之前设置一个指示。在您的 setOnDismissListener() 中执行一个额外的操作(如 getActivity().popupBackStack())。

The advantage of this solution is that you can create your own CustomPopupWindow and implement this strategy. You can hide this implementation in your custom popup window.

此解决方案的优点是您可以创建自己的 CustomPopupWindow 并实施此策略。您可以在自定义弹出窗口中隐藏此实现。

Step 1: add near to your instantiation of your Popup Window:

第 1 步:在弹出窗口的实例化附近添加:

boolean isClickHandled = false; 
popupWindow.setOutsideTouchable(true);
popupWindow.setBackgroundDrawable(new ShapeDrawable());
popupWindow.setTouchInterceptor(new View.OnTouchListener() { // or whatever you want
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        isClickHandled = true;
        return false;
    }
});

If you have buttons inside your popupWindow, have the setOnClickListener.onClick set the isClickHandled = true and dismiss().

如果您的 popupWindow 中有按钮,请在 setOnClickListener.onClick 中设置 isClickHandled = true 和dismiss()。

In your onDismissListener do something like:

在您的 onDismissListener 中执行以下操作:

popupWindow.setOnDismissListener(() -> {
        popupWindow.dismiss();
        if ( !isClickHandled) {
            MainActivity.mainActivity.getSupportFragmentManager().popBackStack();
        }
    });