检测后退按钮但不解除对话碎片

use*_*652 65 android dialog dialogfragment

我有一个浮动对话框的对话框片段,其中包含一个特殊的键盘,当用户按下EditText字段时会弹出(正常的IME停止显示).

当用户按下后退按钮(就像使用普通的IME服务一样)时,我希望键盘被解除(visibility = GONE),但对话框仍然可见.然而,就我在SO和其他地方的相当广泛的阅读中所看到的,似乎没有办法做到这一点.

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

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

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

有没有办法做到这一点?或者,为了Fragment系统的目的,是否可以访问完全围起来的关键事件的检测?

小智 142

最好的方法和最干净的方法是在onCreateDialog()中创建的对话框中覆盖onBackPressed().

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

  • DialogFragments包装一个Dialog - onCreateDialog创建该对话框.它适用于DialogFragments. (9认同)
  • The only solution I found that actually works properly. (7认同)
  • 这在DialogFragments中不起作用,因为DialogFragment类中没有onBackPressed(). (6认同)

Jua*_*nez 66

我遇到了与你相同的问题,我已经修复了将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
        }
    });
Run Code Online (Sandbox Code Playgroud)

在这里你可以找到的一个问题是这个代码将被执行两次:一个是用户按下后退按钮而另一个是当他离开按下它时.在这种情况下,您必须按事件过滤:

@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
        }
    });
}
Run Code Online (Sandbox Code Playgroud)


Bra*_*don 18

作为Juan Pedro Martinez的回答的补遗,我认为在查看这个帖子时澄清一个特定的问题(我有一个问题)会很有帮助.

如果你想创建一个新的DialogFragment,并且让用户只能使用后退按钮取消它,这会消除随机屏幕触摸过早取消片段,那么这就是你要使用的代码.

在您调用DialogFragment的代码中,您需要将可取消设置设置为false,以便NOTHING解散片段,不会出现杂散屏幕触摸等.

DialogFragment mDialog= new MyDialogFragment();
mDialog.setCancelable(false);
mDialog.show(getFragmentManager(), "dialog");
Run Code Online (Sandbox Code Playgroud)

然后,在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;
         }
   });
Run Code Online (Sandbox Code Playgroud)

现在你的对话框将被调用"setCancelable"为false,这意味着什么都没有(没有外部点击)可以取消它并关闭它,并允许(从对话框本身内)只有后退按钮关闭它.

Ganbatte!


小智 9

怎么没有人建议这个?

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;
}
Run Code Online (Sandbox Code Playgroud)


小智 8

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

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

    // Add you codition
}
Run Code Online (Sandbox Code Playgroud)

  • 请注意,使用这种方法您无法处理 DialogFragment 是否会被关闭。您只需收到将被驳回的通知 (3认同)

Tom*_*dek 8

由于AppCompat 1.5.0-alpha01 AppCompatDialog现在正在扩展ComponentDialog来源)。这意味着DialogFragment您现在可以轻松地(从片段的对话框中)获得一个有效的值OnBackPressedDispatcher,允许您自己处理后退按键。

科特林:

class MyFragment: androidx.fragment.app.DialogFragment() {

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        (dialog as androidx.activity.ComponentDialog)
            .onBackPressedDispatcher
            .addCallback(viewLifecycleOwner) {
                // handle back press
            }
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:当您添加回调时,它可以防止通过按“后退”自动关闭/取消对话框。


and*_*per 5

创建对话框时,覆盖 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
                    ...
            }
        };
Run Code Online (Sandbox Code Playgroud)


Ben*_*nny 5

防止取消 DialogFragment:

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