63

当我单击列表活动中的项目时,会显示一个弹出窗口。问题是后退键没有关闭它。我尝试在我的列表活动中捕获后退键,但它没有注册它......然后我尝试将 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;
        }
    });

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

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

但是那个听众也没有开火。你能帮助我吗?我没有想法:)

4

11 回答 11

150

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

扩展深奥的答案:

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

于 2010-06-26T04:24:19.353 回答
39

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

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);
于 2011-11-16T06:34:27.403 回答
8

对于新项目,最好使用

popupWindow.setBackgroundDrawable(new ColorDrawable());

代替

popupWindow.setBackgroundDrawable(new BitmapDrawable());

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

于 2014-08-26T14:31:32.900 回答
5

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

pw.setBackgroundDrawable(new BitmapDrawable());

至 :

pw.setBackgroundDrawable(new ShapeDrawable());

整个工作将是这样的:

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);
于 2014-05-22T09:12:01.580 回答
5

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

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

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

祝你好运!

于 2010-11-08T08:10:26.257 回答
4

就用这个

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

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

于 2014-05-27T02:46:36.807 回答
3

我希望这对你有帮助

 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;
        }
    });
于 2011-11-18T07:25:12.017 回答
1

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

于 2015-03-13T02:01:41.927 回答
0
    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+"");

        }
    });
}

这个问题是popupwindow的消息机制决定的,因为它是阻尼式的。祝你好运

于 2013-08-22T02:48:19.417 回答
0
pw.setBackgroundDrawable(new ColorDrawable());  

必须在setContentView之前写

这对我有用。

于 2018-12-28T13:39:13.723 回答
0

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

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

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

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

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

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

popupWindow.setOnDismissListener(() -> {
        popupWindow.dismiss();
        if ( !isClickHandled) {
            MainActivity.mainActivity.getSupportFragmentManager().popBackStack();
        }
    });
于 2020-05-23T13:07:09.907 回答