简体   繁体   English

Android弹出窗口关闭

[英]Android popup window dismissal

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.我尝试在我的列表活动中捕获返回键,但它没有注册它......然后我尝试将一个 onkeylistener 注册到我传递给我的弹出窗口的视图中。 Like this:像这样:

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 :)我没有想法:)

This is because the popup window does not respond to onTouch or onKey events unless it has a background that != null.这是因为弹出窗口不会响应 onTouch 或 onKey 事件,除非它的背景为 != null。 Check out some code I wrote to help with this.查看我编写的一些代码来帮助解决这个问题。 In the basic case you can to call PopupWindow#setBackgroundDrawable(new BitmapDrawable()) to force it to act the way you expect.在基本情况下,您可以调用PopupWindow#setBackgroundDrawable(new BitmapDrawable())以强制它按照您期望的方式运行。 You won't need your own onKey listener.您不需要自己的 onKey 侦听器。 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.如果您希望它在用户单击窗口边界外时消失,您可能还需要调用PopupWindow#setOutsideTouchable(true)

Extended esoteric answer:扩展深奥的答案:

The reason the background cannot be null is because of what happens in PopupWindow#preparePopup .背景不能为空的原因是因为PopupWindow#preparePopup发生的事情。 If it detects background != null it creates an instance of PopupViewContainer and calls setBackgroundDrawable on that and puts your content view in it.如果它检测到background != null它会创建一个PopupViewContainer的实例并调用setBackgroundDrawable并将您的内容视图放入其中。 PopupViewContainer is basically a FrameLayout that listens for touch events and the KeyEvent.KEYCODE_BACK event to dismiss the window. PopupViewContainer基本上是一个FrameLayout ,它侦听触摸事件和KeyEvent.KEYCODE_BACK事件以关闭窗口。 If background == null, it doesn't do any of that and just uses your content view.如果 background == null,它不会执行任何操作,只会使用您的内容视图。 You can, as an alternative to depending on PopupWindow to handle that, extend your root ViewGroup to behave the way you want.作为依赖PopupWindow处理该问题的替代方法,您可以扩展您的根ViewGroup以按照您想要的方式行事。

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);

For new projects it's better to use对于新项目,最好使用

popupWindow.setBackgroundDrawable(new ColorDrawable());

instead of代替

popupWindow.setBackgroundDrawable(new BitmapDrawable());

as BitmapDrawable is deprecated.因为 BitmapDrawable 已被弃用。 Also, it's better than ShapeDrawable in this case.此外,在这种情况下,它比 ShapeDrawable 更好。 I noticed that when PopupWindow is a rectangle with rounded corners, ShapeDrawable fills corners with black.我注意到当 PopupWindow 是一个带圆角的矩形时,ShapeDrawable 用黑色填充角落。

For the new searchers , as creating a new BitmapDrawable is 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 BitmapDrawable (不The constructor BitmapDrawable() is deprecated ),因此您必须将其更改为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);

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, eg 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!祝你好运!

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() ,因为它会在需要重绘屏幕时尝试绘制形状时渲染缓慢。

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;
        }
    });

您需要为PopupWindow添加setBackgroundDrawable(new BitmapDrawable())

    private void initPopupWindow() {  
    // TODO Auto-generated method stub  

    View view = getLayoutInflater().inflate(R.layout.main_choice, null);  

    ListView main_menu_listview = (ListView) view.findViewById(R.id.main_menu_listview);  

    ShowMainChoice madapter = new ShowMainChoice(context);
    main_menu_listview.setAdapter(madapter);

    int width = (int)getWindowManager().getDefaultDisplay().getWidth()/2;
    popupWindow = new PopupWindow(view, width,WindowManager.LayoutParams.WRAP_CONTENT);  
    popupWindow.setBackgroundDrawable(new BitmapDrawable());//this is important,如果缺少这句将导致其他任何控件及监听都得不到响应
    popupWindow.setOutsideTouchable(true);
    popupWindow.setFocusable(true);

    main_menu_listview.setOnItemClickListener(new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,long arg3) {
            // TODO Auto-generated method stub

            Log.e("++++++>", arg2+"");

        }
    });
}

This problem is popupwindow底层的消息机制决定的,因为它是阻塞式的。Good luck这个问题是popupwindow的消息机制决定的,因为它是真实式的。祝你好运

pw.setBackgroundDrawable(new ColorDrawable());  

must wrote it before setContentView必须在setContentView之前写

This works for me.这对我有用。

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.解决原理:弹窗附近的所有按钮点击都会被拦截,但不会拦截任何BACK按钮。 So, if you have anything in you popupwindow that takes action, then set an indication just before your call to dismiss().因此,如果您的弹出窗口中有任何需要采取行动的内容,请在您调用dismiss() 之前设置一个指示。 In your setOnDismissListener() perform an extra action (like getActivity().popupBackStack()).在您的 setOnDismissListener() 中执行一个额外的操作(如 getActivity().popupBackStack())。

The advantage of this solution is that you can create your own CustomPopupWindow and implement this strategy.此解决方案的优点是您可以创建自己的 CustomPopupWindow 并实施此策略。 You can hide this implementation in your custom popup window.您可以在自定义弹出窗口中隐藏此实现。

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();
        }
    });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM