17

我的Fragment应用中有一个显示DialogFragment.
我在片段中有一个关闭对话框的按钮。但是当我显示 dialogFragment 时,对话框外部的触摸什么也不做,我无法单击对话框片段外部的按钮。

如何允许 DialogFragment 的外部触摸?

4

8 回答 8

25

为了做到这一点,Window应该打开一个允许外部触摸的标志,并且为了美观,应该清除背景暗淡标志。
由于必须在创建对话框后完成,我通过Handler.

@Override
public void onViewCreated(final View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);

    // This is done in a post() since the dialog must be drawn before locating.
    getView().post(new Runnable() {

        @Override
        public void run() {

            Window dialogWindow = getDialog().getWindow();

            // Make the dialog possible to be outside touch
            dialogWindow.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
                    WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
            dialogWindow.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);

            getView().invalidate();
        }
    });
}

此时,外部触摸是可能的。

如果我们想让它更好并且没有框架,可以添加以下代码:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Hide title of the dialog
    setStyle(STYLE_NO_FRAME, 0);
}
于 2013-03-14T14:18:49.960 回答
7

这是更通用的标志,允许任何操作,而不仅仅是触摸操作

window.setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
        WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
于 2014-12-20T12:26:03.733 回答
1

我找到了另一种方法来处理外部触摸时的解雇。请检查下面的代码示例,这肯定会起作用,

@Override
public void onStart() {
    // mDialogView is member variable
    mDialogView = getView();
    mDialogView.setOnTouchListener(new View.OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            float eventX = event.getRawX();
            float eventY = event.getRawY();

            int location[] = new int[2];
            mDialogView.getLocationOnScreen(location);

            if (eventX < location[0] || eventX > (location[0] + mDialogView.getWidth()) || eventY < location[1]
                    || eventY > location[1] + mDialogView.getHeight()) {
                dismiss();
                return true;
            }
            return false;
        }
    });
}

就我而言,我得到 getDialog() 不是空值,但 getDialog().dismiss() 不起作用。此外,上面标记的解决方案在我的情况下也不起作用。所以,我采用了这种方法。

于 2015-01-20T10:28:48.393 回答
1

根据我上面的小调查,我真的认为这应该是公认的答案:

  @Override
  public Dialog onCreateDialog(Bundle savedInstanceState)
    {
    FragmentActivity act = getActivity();
    AlertDialog.Builder builder = new AlertDialog.Builder(act);

    // ... do your stuff here

    Dialog dialog = builder.create();

    dialog.setCanceledOnTouchOutside(false);

    Window window = dialog.getWindow();

    if( window!=null )
      {
      window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
                      WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
      window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
      }

    return dialog;
    }

即把flags的设置移到onCreateDialog()的最后,加上setCancelOnTouchOutside(false)。

接受的答案不适用于运行 Android 9 和 10(很可能是 11)的三星手机。看起来在这些系统上,三星已经改变了一些东西,使得设置这些标志只有在很早设置时才有效。

以上适用于任何地方,包括谷歌模拟器、LG Nexus 5X、HTC Desire 12、谷歌 Pixel 6、几部华为手机,以及我测试过的所有(大约 20 部)三星手机。

于 2020-04-14T22:15:59.110 回答
1

我已经测试了接受的(Yaniv's)答案

Galaxy Tab A 9.7 Android 7.1.1: ok
Galaxy Tab A 8.0 Android 7    : ok
Galaxy Tab S4 Android 9       : no touch outside DialogFragment
Galaxy S5 Android 6.0.1       : ok
Galaxy Tab S2 Android 7       : ok
Galaxy Tab S3 Android 9       : no touch outside DialogFragment
Galaxy Tab S4 Android 9       : no touch outside DialogFragment
Galaxy Note Edge Android 6.0.1: ok
Galaxy Note4 Android 6.0.1    : ok

它看起来确实不适用于 Android 9。当我说“不起作用”时,我的意思是当我尝试单击 DialogFragment 外部的按钮时,它的 onClick() 方法根本不会被调用。

编辑:根据我的发现(在评论中),我认为以下应该是公认的答案。以下适用于我测试过的所有地方,包括模拟器、Google Pixel 6、LG Nexus 5X、HTC Desire 12、大约 5 部华为手机和大约 20 部运行 Android 5 到 10 的三星手机。

public Dialog onCreateDialog(Bundle savedInstanceState)
    {
    FragmentActivity act = getActivity();
    AlertDialog.Builder builder = new AlertDialog.Builder(act);

    // ... do your stuff here....

    Dialog dialog = builder.create();

    dialog.setCanceledOnTouchOutside(false);

    Window window = dialog.getWindow();

    if( window!=null )
      {
      window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
                      WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
      window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
      }

    return dialog;
    }
于 2020-04-13T11:58:28.500 回答
0

您需要根据需要设置适当的样式。您可以在官方文档中阅读有关 FragmentDialogs 样式的更多信息。

我相信您可以使用以下样式:

  • STYLE_NO_FRAME
于 2013-03-13T11:51:48.503 回答
0

@yaniv 提供了答案。但如果你愿意,这里有一个片段,你可以得到相同的结果,但不需要将 a 发布Runnable到 root View

@NonNull
@Override
public Dialog onCreateDialog(@Nullable final Bundle savedInstanceState) {
    final Dialog dialog = super.onCreateDialog(savedInstanceState);
    dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
    return dialog;
}
于 2019-07-18T12:04:42.923 回答
0

好吧,让我们具体一点。如果你想使用外部视图,那么你不应该使用对话框片段,而是像这样使用片段。

 FragmentTransaction transaction = fragmentManager.beginTransaction();
    // For a little polish, specify a transition animation
    transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
    // To make it fullscreen, use the 'content' root view as the container
    // for the fragment, which is always the root view for the activity
    transaction.add(android.R.id.content, newFragment)
               .addToBackStack(null).commit();

并制作布局 wrap_content,它显然看起来像 Dialog,默认情况下它被放置在屏幕的顶部。

欲了解更多详情,请访问这里

于 2016-03-04T11:36:12.323 回答