Android弹出窗口被解雇

时间:2010-06-25 20:30:34

标签: android popupwindow

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

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

11 个答案:

答案 0 :(得分:148)

这是因为弹出窗口不响应onTouch或onKey事件,除非它的背景为!= null。 Check out some code I wrote帮助解决这个问题。在基本情况下,您可以调用PopupWindow#setBackgroundDrawable(new BitmapDrawable())强制它按您期望的方式行事。您不需要自己的onKey侦听器。如果您希望在用户点击窗口边界外部时离开,则可能还需要调用PopupWindow#setOutsideTouchable(true)

扩展深奥的答案:

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

答案 1 :(得分:36)

按照以下方式运行正常:

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

答案 2 :(得分:7)

对于新项目,最好使用

popupWindow.setBackgroundDrawable(new ColorDrawable());

而不是

popupWindow.setBackgroundDrawable(new BitmapDrawable());

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

答案 3 :(得分: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);
} 
祝你好运!

答案 4 :(得分:4)

对于新搜索者,由于现在不允许创建new BitmapDrawableThe constructor BitmapDrawable() is deprecated),因此您必须将其更改为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);

答案 5 :(得分:4)

只需使用此

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

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

答案 6 :(得分: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;
        }
    });

答案 7 :(得分:1)

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

答案 8 :(得分: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底层的消息机制决定的,因为它是阻塞式的。祝你好运

答案 9 :(得分:0)

concurrently

必须在 setContentView

之前编写

这对我有用。

答案 10 :(得分:0)

您是要结合使用弹出式窗口关闭功能和 BACK按钮的良好功能,还是可以考虑以下解决方案。

解决方案原理:您的弹出窗口附近的所有按钮单击都将被拦截,但任何BACK按钮都将不会被拦截。因此,如果您在popupwindow中有任何东西可以采取措施,请在调用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();
        }
    });