检测后退按钮,但不关闭对话框片段


77

我有一个浮动对话框的dialogfragment,其中包括一个特殊的键盘,当用户在EditText字段中按下时,该键盘会弹出(正常IME不再显示)。

我希望当用户按下“后退”按钮(就像使用常规IME服务一样)时关闭键盘(可见性= GONE),但对话框保持可见。但是,据我从SO和其他方面的相当广泛的阅读中可以看出,似乎没有办法做到这一点。

如果我将对话框设置为不可取消,那么onCancel()或onDismiss()不会通知我,因为该对话框不可取消。

如果我将对话框设置为可取消,则会收到通知,但该对话框将被关闭。

我无法将onKeyListener附加到片段中的对话框,因为它已被系统替换,以便片段可以处理对话框的生命周期。

有什么办法吗?还是出于Fragment系统的目的而完全阻止了对关键事件的检测?

Answers:


175

最好的方法是在onCreateDialog()中创建的对话框中覆盖onBackPressed()。

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    return new Dialog(getActivity(), getTheme()){
        @Override
        public void onBackPressed() {
            //do your stuff
        }
    };
}

9
我发现唯一可行的解​​决方案。
Yoann Hercouet 2014年

6
但是,这在DialogFragments中不起作用,因为DialogFragment类中没有onBackPressed()。
Glen Pierce 2015年

10
DialogFragments包装一个对话框-onCreateDialog创建此对话框。它可以在DialogFragments中工作。
汤姆(Tom)”

我只能确认这是最好,最简单的解决方案。感谢您分享@Ian Wong
Menion Asamm,2016年

1
绝对应该是一个可以接受的答案。迄今为止最原生的解决方案!
egorikem '17

72

我遇到了与您相同的问题,并且已修复将onKeyListener附加到dialogfragment的问题。

onResume()DialogFragment扩展的类的方法中放入以下代码:

    getDialog().setOnKeyListener(new OnKeyListener()
    {
        @Override
        public boolean onKey(android.content.DialogInterface dialog, int keyCode,android.view.KeyEvent event) {

            if ((keyCode ==  android.view.KeyEvent.KEYCODE_BACK))
                {
                     //Hide your keyboard here!!!
                     return true; // pretend we've processed it
                }
            else 
                return false; // pass on to be processed as normal
        }
    });

在这里,您会发现的问题之一是该代码将执行两次:一个在用户按下“后退”按钮时出现,另一个在用户离开时按下该代码时执行。在这种情况下,您必须按事件过滤:

@Override
public void onResume() {
    super.onResume();

    getDialog().setOnKeyListener(new OnKeyListener()
    {
        @Override
        public boolean onKey(android.content.DialogInterface dialog, int keyCode,
                android.view.KeyEvent event) {

            if ((keyCode ==  android.view.KeyEvent.KEYCODE_BACK))
            {
                //This is the filter
                if (event.getAction()!=KeyEvent.ACTION_DOWN)
                        return true;
                else
                {
                    //Hide your keyboard here!!!!!!
                    return true; // pretend we've processed it
                }
            } 
            else 
                return false; // pass on to be processed as normal
        }
    });
}

我没有使用过滤器,而是添加了getDialog()。setOnKeyListener(null)来阻止第二个调用。
卢卡斯·阿雷菲特

24

作为胡安·佩德罗·马丁内斯(Juan Pedro Martinez)回答的附录,我认为在研究该主题时阐明一个具体问题(我曾经提出过的问题)会有所帮助。

如果您希望创建一个新的DialogFragment并拥有它,以便用户只能使用后退按钮将其取消,从而消除了过早取消片段的随机屏幕触摸,那么您将使用此代码。

在调用DialogFragment的任何代码中,都需要将cancelable设置设置为false,以使NOTHING消除该片段,不会产生杂乱的屏幕触摸等。

DialogFragment mDialog= new MyDialogFragment();
mDialog.setCancelable(false);
mDialog.show(getFragmentManager(), "dialog");

然后,在DialogFragment(在本例中为MyDaialogFragment.java)中,添加onResume覆盖代码以使对话框侦听“后退”按钮。当按下它时,将执行dismiss()关闭该片段。

@Override
 public void onResume() 
 {
     super.onResume();

     getDialog().setOnKeyListener(new OnKeyListener()
     {
         @Override
         public boolean onKey(android.content.DialogInterface dialog, 
                              int keyCode,android.view.KeyEvent event) 
         {
              if ((keyCode ==  android.view.KeyEvent.KEYCODE_BACK))
              {
                   // To dismiss the fragment when the back-button is pressed.
                   dismiss();
                   return true;
              }
              // Otherwise, do nothing else
              else return false;
         }
   });

现在,您的对话框将被调用,“ setCancelable”为false,这意味着没有任何东西(没有外部单击)可以取消并关闭它,并且(从对话框本身内部)仅允许返回按钮将其关闭。

甘巴特!


1
完美,谢谢,我想在保持后退按钮功能的同时防止意外的外部点击,对我来说,我要做的就是在DialogFragment中onCreateView的对话框实例上设置setCancelable(false)。
Meanman '16

1
谢谢,这个答案最适合我的情况。
阿拉朱

16

没人建议吗?

public Dialog onCreateDialog(Bundle savedInstanceState) {
  Dialog dialog = super.onCreateDialog(savedInstanceState);

  // Add back button listener
  dialog.setOnKeyListener(new Dialog.OnKeyListener() {
    @Override
    public boolean onKey(DialogInterface dialogInterface, int keyCode, KeyEvent keyEvent) {
      // getAction to make sure this doesn't double fire
      if (keyCode == KeyEvent.KEYCODE_BACK && keyEvent.getAction() == KeyEvent.ACTION_UP) {
        // Your code here
        return true; // Capture onKey
      }
      return false; // Don't capture
    }
  });

  return dialog;
}

13

使用Fragment onCancel覆盖方法。按下时会调用它。这是一个示例:

@Override
public void onCancel(DialogInterface dialog) {
    super.onCancel(dialog);

    // Add you codition
}

2
请注意,使用这种方法无法处理DialogFragment是否被关闭。您可以得到通知,它将被取消
Leo Droidcoder

的确,@ Leo Droidcoder知道如何在无法取消对话框片段之前拦截后退按钮吗?
matdev

3

创建对话框时,请同时覆盖onBackPressed和onTouchEvent:

        final Dialog dialog = new Dialog(activity) {
            @Override
            public boolean onTouchEvent(final MotionEvent event) {
                //note: all touch events that occur here are outside the dialog, yet their type is just touching-down
                boolean shouldAvoidDismissing = ... ;
                if (shouldAvoidDismissing) 
                    return true;
                return super.onTouchEvent(event);
            }

            @Override
            public void onBackPressed() {
                boolean shouldAvoidDismissing = ... ;
                if (!shouldSwitchToInviteMode)
                    dismiss();
                else
                    ...
            }
        };

0

使用带有closeActivity标志的DialogFragment的onDismiss()回调

private var closeActivity: Boolean = true    

override fun onDismiss(dialog: DialogInterface?) {
        super.onDismiss(dialog)

        if (closeActivity) {
            activity!!.finish()
        }
    }

0

防止取消DialogFragment:

dialog.setCanceledOnTouchOutside(false)
dialog.setCancelable(false)
dialog.setOnKeyListener { dialog, keyCode, event ->
    keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_UP
}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.